From C++ Draft Standard N3337:
7.1.6.2 Simple type specifiers
4 The type denoted by
decltype(e)
is defined as follows:— 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 bye
. If there is no such entity, or ife
names a set of overloaded functions, the program is ill-formed;— otherwise, if e is an xvalue,
decltype(e)
isT&&
, whereT
is the type ofe
;— otherwise, if e is an lvalue,
decltype(e)
isT&
, whereT
is the type ofe
;
If I understand the above correctly,
int a;
decltype(a) b = 10; // type of b is int
int* ap;
decltype(*ap) c = 10; // Does not work since type of c is int&
Can you explain, or point to some documentation that explains, why decltype(*ap)
couldn't have been just int
?
The decltype type specifier, together with the auto keyword, is useful primarily to developers who write template libraries. Use auto and decltype to declare a template function whose return type depends on the types of its template arguments.
Decltype keyword in C++ Decltype stands for declared type of an entity or the type of an expression. It lets you extract the type from the variable so decltype is sort of an operator that evaluates the type of passed expression. SYNTAX : decltype( expression )
decltype is a compile time evaluation (like sizeof ), and so can only use the static type.
decltype returnsIf what we pass to decltype is the name of a variable (e.g. decltype(x) above) or function or denotes a member of an object ( decltype x.i ), then the result is the type of whatever this refers to.
The standardization effort of decltype
was a herculean effort spanning many years. There were 7 versions of this paper before the committee finally accepted it. The versions were:
Remarkably, the seeds of the behavior which you question are in the very first revision: N1478, which introduces the need for "two types of typeof: either to preserve or to drop references in types."
This paper goes on to give a rationale for the reference-preserving variant, including this quote:
On the other hand, the reference-dropping semantics fails to provide a mechanism for exactly expressing the return types of generic functions, as demonstrated by Strous- trup [Str02]. This implies that a reference-dropping typeof would cause problems for writers of generic libraries.
There is no substitute for reading through these papers. However one might summarize that decltype
serves two purposes:
For the second use case, recall that expressions are never reference types, but are instead one of lvalues, xvalues, or prvalues. By convention, when decltype
is reporting the type of an lvalue expression, it makes the type an lvalue reference, and when the expression is an xvalue, the reported type becomes an rvalue reference.
In your example, *ap
is an expression, whereas a
is an identifier. So your example makes use of both use cases, as first introduced in N1478.
It is also instructive to note that decltype
was not designed in isolation. The rest of the C++ language was evolving during this time period (e.g. rvalue references), and the design of decltype
was iterated to keep pace.
Also note that once the decltype
proposal was accepted, it continued (and continues to this day) to evolve. See this list of issues:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_index.html
specifically section 7.1.6.2 (which is the section where the bulk of the decltype
specification lives).
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