The following is a contrived example of the actual code:
int** Ptr = 0;
decltype(Ptr[0]) Test = (int*)0;
I get the error:
In addition to all the other answers, you may also just use
int ** ptr = 0;
decltype(+ptr[0]) test = (int*)0;
// (+*p) is now an r-value expression of type int, rather than int&
Some of the rules used here are:
Also note that if the name of an object is parenthesized, it is treated as an ordinary lvalue expression, thus decltype(x) and decltype((x)) are often different types. [an excerpt from https://en.cppreference.com/w/cpp/language/decltype]
seen at http://www.cplusplus.com/forum/beginner/149331/
more on decltype here : https://en.cppreference.com/w/cpp/language/decltype
If we go to the draft C++ standard section 7.1.6.2
Simple type specifiers [dcl.type.simple] and see what he cases are. For decltype it starts out saying:
For an expression e, the type denoted by decltype(e) is defined as follows:
We see that in this case the expression is not a id-expression nor a class member access, which would give the result you expected(emphasis mine):
- if e is an unparenthesized id-expression or an unparenthesized class member access (5.2.5), 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;
but the result is an lvalue:
- otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;
which results in a reference.
As M.M point out std::remove_reference could be used to obtain the result you want:
std::remove_reference<decltype(Ptr[0])>::type Test = (int*)0;
As T.C. points out std::decay is also an option and is shorter:
std::decay<decltype(Ptr[0])>::type Test = (int*)0;