在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 指针