如何在代码中检查某个值是否为常量?——巧妙利用模板来实现参数的常性检查。

在C++的<type_traits>标头下定义一系列类,以获取有关编译时间的类型信息。

  • Helper classes:用于帮助创建编译时常数的标准类。
  • Type traits:以编译时常量值的形式获取类型的特征的类。
  • Type transformations:通过将特定的转换应用于现有类型来获取新类型的类。

具体可参考《https://docs.microsoft.com/zh-cn/cpp/standard-library/type-traits?view=msvc-160

而在<type_traits>中存在一个 is_count 类,可用于判断类型是否为常数。参考示例如下:

// std__type_traits__is_const.cpp
// compile with: /EHsc
#include <type_traits>
#include <iostream>

struct trivial
{
    int val;
};

int main()
{
    std::cout << "is_const<trivial> == " << std::boolalpha
        << std::is_const<trivial>::value << std::endl;
    std::cout << "is_const<const trivial> == " << std::boolalpha
        << std::is_const<const trivial>::value << std::endl;
    std::cout << "is_const<int> == " << std::boolalpha
        << std::is_const<int>::value << std::endl;
    std::cout << "is_const<const int> == " << std::boolalpha
        << std::is_const<const int>::value << std::endl;

    return (0);
}

/* 输出结果
is_const<trivial> == false
is_const<const trivial> == true
is_const<int> == false
is_const<const int> == true
*/

因此,我们可以使用以下的语法来判断当前变量是否可以作为变量使用。

int ia = 10;			// 普通变量
int* const p = &ia;		// 指针常量
const int* cp_i = &ia;	// 常量指针		const point
const int& clr_ia = ia;	// 常量左值引用 const lvalue reference
int&& rr_ia = ia + 10;	// 右值引用		"right value" reference
const int&& cr_ca = ia + 10;	// 常量右值引用 const rvalue reference

std::cout << "is_const<ia> == " << std::boolalpha
	<< std::is_const<decltype(ia)>::value << std::endl;
ia = 100;		// 可修改,不是常量
std::cout << "is_const<p> == " << std::boolalpha
	<< std::is_const<decltype(p) >::value << std::endl;
// p = new int(20); 不可修改,是常量
std::cout << "is_const<*cp_i> == " << std::boolalpha
	<< std::is_const<decltype(*cp_i)>::value << std::endl;
// *cp_i = 100;	    不可修改,是常量
std::cout << "is_const<clr_ia> == " << std::boolalpha
	<< std::is_const<decltype(clr_ia)>::value << std::endl;
// clr_ia = 100;    不可修改,是常量
std::cout << "is_const<rr_ia> == " << std::boolalpha
	<< std::is_const<decltype(rr_ia)>::value << std::endl;
rr_ia = 100;	// 可修改,不是常量
std::cout << "is_const<cr_ca> == " << std::boolalpha
	<< std::is_const<decltype(cr_ca)>::value << std::endl;
// cr_ca = 100;	    不可修改,是常量

在这里插入图片描述
可以发现结果并不完全正确。我们发现对于引用类型,is_const都不认为是常量。

而对于指针类型来说,因为指针类型没有实体,指针的值是依靠它所指之物来体现的。因此,对于 const int* 类型来说,它表示指针所指向之物是不可修改的,我们认为指针指向了常量,即上述的 cp_i 应该是个常量,但在这里并没有体现出来。

为了更加清晰直观,我们直接用类型来展示以上结果,发现针对引用类型与指针类型 is_const都不能很好给出结果。
在这里插入图片描述

可这样的输出结果并不是我们所期望的结果。

而在Stack Overflow 上我们找到了答案,参考《calling version of is_const<> but for variables instead of types, in one line》 中的回答,使用模板构建一个检查参数类型是否具有常性的函数。

函数模型如下:

template<typename T>
constexpr bool check_const(const T* x) noexcept { return true; }

template<typename T>
constexpr bool check_const(T* x) noexcept { return false; }

template<typename T>
constexpr bool check_const(const T& x) noexcept { return true; }

template<typename T>
constexpr bool check_const(T& x) noexcept { return false; }

在这里插入图片描述
这里需要说明的一点是,const int * 类型表示的是指针指向一个const int 类型,因为指针依托所指变量存在,所以这里给出的 const int * 类型的指针实际上是给出它所指空间的常性结果。

如果你对指针与const相结合还不太熟悉的话,我们在这里再复习一遍:

向后阅读规则(以 *为界限,从右向左看。 *左边为所指空间的类型,*右边为指针类型):

  • int* - 指向 int的指针
  • int const * - 指向 const int 的指针 (等价于const int*)
  • int * const - 指向 int 的 const 指针
  • int const * const - 指向 const int 的const 指针
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我叫RT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值