I was working on a program recently which goes like this :-
#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;
}
The output of this program is :-
i i
false
false
As visible clearly, typeid specifies that *p & x are of same type & even using *sp2 = 7 generates an error. Then why do std::is_same & std::is_const differ from it ?
You are running into two different issues here. First case we can see from the cppreference entry for typeid that top level const qualifiers are ignored:
In all cases, cv-qualifiers are ignored by typeid (that is, typeid(T)==typeid(const T))
We can see from the cppreference entry for decltype, the following rules that are relevant here are:
- 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&;
[...]
So *p is an expression and is not a id-expression nor a class member access unlike let's say the following case:
const int x = 0 ;
std::cout << is_const<decltype(x)>::value << "\n" ;
^^^^^^^^^^^
Which would yield true since x is an id-expression.
So *p being an expression will yield T& since the result is an lvalue. The reference will not itself be const so is_const is correct, on the other hand this will return the result you desire:
is_const<std::remove_reference<decltype(*p)>::type>::value
^^^^^^^^^^^^^^^^^^^^^
Note the use of std::remove_reference.
T.C. point out that std::remove_pointer could also be effective here:
is_const<std::remove_pointer<decltype(p)>::type>::value
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With