使用type_traits

时间:2015-11-14 15:50:30

标签: c++ typetraits

我最近正在制作一个类似的程序: -

#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&amp; x属于同一类型&amp;即使使用*sp2 = 7也会产生错误。那么为什么std::is_same&amp; std::is_const与此不同?

1 个答案:

答案 0 :(得分:3)

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

  

在所有情况下,typeid都会忽略cv限定符(即typeid(T)== typeid(const T))

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

  
      
  1. f参数是未加密码的id-expression或未加密码的类成员访问,然后decltype生成此表达式命名的实体的类型。 [...]
  2.   
  3. 如果参数是T和
  4. 类型的任何其他表达式         

    [...]

         
        
    • 如果表达式的值类别是左值,则decltype产生T&amp ;;
    •   
         

    [...]

所以*p是一个表达式,不是id-expression,也不是类成员访问,不像让我们说下面的情况:

const int x = 0 ;
std::cout << is_const<decltype(x)>::value << "\n" ; 
                      ^^^^^^^^^^^

由于x是一个id-expression,所以会产生真的。

因此,作为表达式的*p将产生T&,因为结果是左值。引用本身不是const,因此is_const是正确的,另一方面,这将返回您想要的结果:

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