decltype
deduces the type of expression, unless it is applied to a variable, in which case it deduces the type of that variable:
The type denoted by decltype(e)
is defined as follows:
— if e is an unparenthesized id-expression or an unparenthesized class member access, decltype(e)
is the type of the entity named by e
. If there is no such entity, or if e
names a set of overloaded functions, the program is ill-formed;
— otherwise, if e
is an xvalue, decltype(e)
is T&&
, where T
is the type of e
;
— otherwise, if e
is an lvalue, decltype(e)
is T&
, where T
is the type of e
;
— otherwise, decltype(e)
is the type of e
.
§7.1.6.2 [dcl.type.simple]
Dereferencing a pointer yields an lvalue, and therefore decltype
will deduce an lvalue reference to the type of the pointee:
The unary *
operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points.
§5.3.1 [expr.unary.op]
Therefore decltype(*p)
, for some pointer p
, deduces an lvalue reference to the type of the pointee.
If you wish to get the type of the pointee from some pointer p
, you can use:
std::remove_pointer<decltype(p)>::type
Or:
std::remove_reference<decltype(*p)>::type
Or, in your example, you can simply say foo
, type deduction is not required.