使用 type_traits 检查常量
checking constness using type_traits
我最近在做一个程序,它是这样的:-
#include <iostream>
#include <memory>
#include <type_traits>
#include <typeinfo>
using namespace std;
int main()
{
shared_ptr<int> sp1 = make_shared<int>(5);
shared_ptr<const int> sp2 (sp1);
const int x = 8;
// *sp2 = 7; // error: assignment of read-only location 'sp2.std::shared_ptr<const int>::<anonymous>.std::__shared_ptr<_Tp, _Lp>::operator*<const int, (__gnu_cxx::_Lock_policy)2u>()'
auto p = sp2.get();
cout << typeid(x).name() << '\t' << typeid(*p).name() << '\n';
cout << boolalpha;
cout << is_const<decltype(*p)>::value << '\n' << is_same<const int, decltype(*p)>::value;
return 0;
}
这个程序的输出是:-
i i
false
false
很明显,typeid
指定 *p
和 x
是同一类型,即使使用 *sp2 = 7
也会产生错误。那为什么 std::is_same
和 std::is_const
不同呢?
您 运行 遇到了两个不同的问题。我们可以从 typeid 的 cppreference 条目中看到第一种情况,顶级 const 限定符被忽略:
In all cases, cv-qualifiers are ignored by typeid (that is, typeid(T)==typeid(const T))
我们可以从 decltype 的 cppreference 条目中看到,以下与此处相关的规则是:
- f the argument is an unparenthesized id-expression or an unparenthesized class member access, then decltype yields the type of the entity named by this expression. [...]
- If the argument is any other expression of type T, and
[...]
- if the value category of expression is lvalue, then decltype yields T&;
[...]
所以 *p
是一个表达式,不是 id 表达式,也不是 class 成员访问,不像下面的情况:
const int x = 0 ;
std::cout << is_const<decltype(x)>::value << "\n" ;
^^^^^^^^^^^
这会产生 true,因为 x
是一个 id 表达式。
所以 *p
作为一个表达式将产生 T&
因为结果是一个左值。引用本身不会是常量,所以 is_const
是正确的,另一方面这将 return 你想要的结果:
is_const<std::remove_reference<decltype(*p)>::type>::value
^^^^^^^^^^^^^^^^^^^^^
的使用
T.C。指出 std::remove_pointer 在这里也可能有效:
is_const<std::remove_pointer<decltype(p)>::type>::value
我最近在做一个程序,它是这样的:-
#include <iostream>
#include <memory>
#include <type_traits>
#include <typeinfo>
using namespace std;
int main()
{
shared_ptr<int> sp1 = make_shared<int>(5);
shared_ptr<const int> sp2 (sp1);
const int x = 8;
// *sp2 = 7; // error: assignment of read-only location 'sp2.std::shared_ptr<const int>::<anonymous>.std::__shared_ptr<_Tp, _Lp>::operator*<const int, (__gnu_cxx::_Lock_policy)2u>()'
auto p = sp2.get();
cout << typeid(x).name() << '\t' << typeid(*p).name() << '\n';
cout << boolalpha;
cout << is_const<decltype(*p)>::value << '\n' << is_same<const int, decltype(*p)>::value;
return 0;
}
这个程序的输出是:-
i i
false
false
很明显,typeid
指定 *p
和 x
是同一类型,即使使用 *sp2 = 7
也会产生错误。那为什么 std::is_same
和 std::is_const
不同呢?
您 运行 遇到了两个不同的问题。我们可以从 typeid 的 cppreference 条目中看到第一种情况,顶级 const 限定符被忽略:
In all cases, cv-qualifiers are ignored by typeid (that is, typeid(T)==typeid(const T))
我们可以从 decltype 的 cppreference 条目中看到,以下与此处相关的规则是:
- f the argument is an unparenthesized id-expression or an unparenthesized class member access, then decltype yields the type of the entity named by this expression. [...]
- If the argument is any other expression of type T, and
[...]
- if the value category of expression is lvalue, then decltype yields T&;
[...]
所以 *p
是一个表达式,不是 id 表达式,也不是 class 成员访问,不像下面的情况:
const int x = 0 ;
std::cout << is_const<decltype(x)>::value << "\n" ;
^^^^^^^^^^^
这会产生 true,因为 x
是一个 id 表达式。
所以 *p
作为一个表达式将产生 T&
因为结果是一个左值。引用本身不会是常量,所以 is_const
是正确的,另一方面这将 return 你想要的结果:
is_const<std::remove_reference<decltype(*p)>::type>::value
^^^^^^^^^^^^^^^^^^^^^
的使用
T.C。指出 std::remove_pointer 在这里也可能有效:
is_const<std::remove_pointer<decltype(p)>::type>::value