我最近正在制作一个类似的程序: -
#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
与此不同?
答案 0 :(得分:3)
您在这里遇到两个不同的问题。我们可以从typeid的cppreference条目看到第一种情况,即忽略顶级const限定符:
在所有情况下,typeid都会忽略cv限定符(即typeid(T)== typeid(const T))
我们可以从decltype的cppreference条目中看到,以下相关规则是:
- f参数是未加密码的id-expression或未加密码的类成员访问,然后decltype生成此表达式命名的实体的类型。 [...]
- 如果参数是T和
类型的任何其他表达式 醇>[...]
- 如果表达式的值类别是左值,则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