使用 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 指定 *px 是同一类型,即使使用 *sp2 = 7 也会产生错误。那为什么 std::is_samestd::is_const 不同呢?

您 运行 遇到了两个不同的问题。我们可以从 typeid 的 cppreference 条目中看到第一种情况,顶级 const 限定符被忽略:

In all cases, cv-qualifiers are ignored by typeid (that is, typeid(T)==typeid(const T))

我们可以从 decltype 的 cppreference 条目中看到,以下与此处相关的规则是:

  1. 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. [...]
  2. 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
         ^^^^^^^^^^^^^^^^^^^^^

注意 std::remove_reference.

的使用

T.C。指出 std::remove_pointer 在这里也可能有效:

is_const<std::remove_pointer<decltype(p)>::type>::value