decltype prints expression type if it does not apply to the variable, in which case it infers the type of this variable:
The type indicated by decltype(e) is defined as follows:
- if e is a non-spheronized identifier or disjoint access to a class member, decltype(e) is the type of object called e . If such an object is absent or if e calls a set of overloaded functions, the program is poorly formed;
- otherwise, if e is the value of x, decltype(e) is T&& , where T is the type of e ;
- otherwise, if e is an lvalue, decltype(e) is T& , where T is a type of e ;
- otherwise decltype(e) is type e .
Β§7.1.6.2 [dcl.type.simple]
Pointer dereferencing gives an lvalue, and therefore decltype prints a lvalue reference to the pointer type:
The unary operator * performs an indirect direction: the expression to which it is applied must be a pointer to the type of the object or a pointer to the type of the function, and the result is the value l that refers to the object or function of the expression.
Β§5.3.1 [expr.unary.op]
Therefore decltype(*p) , for some pointer p displays an lvalue reference to the type of the pointer.
If you want to get a pointer type 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 just say foo , an output type is not required.