I wanted to know why, when I use decltype (* pointer)
, it defines the type of the variable as a reference. For example:
int i = 42, * p = & i;
decltype (* p) c = i;
Now c
is a reference (linked to i
). Why is it a reference and not an integer? I'm reading the book Cpp Primer 5th. Edition. P. 110 says this and I do not understand why.
The decltype type specifier yields the type of a specified expression. 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 function template whose return type depends on the types of its template arguments.
You should use decltype when you want a new variable with precisely the same type as the original variable. You should use auto when you want to assign the value of some expression to a new variable and you want or need its type to be deduced.
In the C++ programming language, decltype is a keyword used to query the type of an expression. Introduced in C++11, its primary intended use is in generic programming, where it is often difficult, or even impossible, to express types that depend on template parameters.
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 )
Contrary to apparently popular belief, *p
has type int
. From [expr.unary.op]
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. If the type of the expression is “pointer to T”, the type of the result is “T”.
The reason decltype(*p)
yields int&
is because of how decltype
works. From [dcl.type.simple]
For an expression e, the type denoted by decltype(e) is defined as follows: [...]
otherwise, 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; [...]
Here id-expression means an expression exactly consisting of a possibly parenthesized name.
Since *p
is an lvalue expression of type int
and not an unparenthesized id-expression nor class member access, the third bullet applies and decltype(*p)
is int&
.
It is worthy to note i
is an unparenthesized id-expression, therefore the first bullet applies and decltype(i)
is int
.
The type that decltype(expr)
will give you depends on the value category of the expression. If expr
is not just an id-expression (i.e. directly the name of a thing), then the rules basically are:
expr
is an xvalue of type T
, then decltype(expr)
will be
T&&
.expr
is an lvalue of type T
, then decltype(expr)
will
be T&
.decltype(expr)
will be T
.In your case, *p
is an lvalue of type int
. Thus decltype(*p)
is defined to be int&
. If you want decltype
to give you int
, you'll have to make the expression be a prvalue, for example by applying the unary + operator like suggested by @Cheers and hth. - Alf in his comment above. However, such arcane constructions might better be avoided in real code. For the sake of readability it might be better to just use std::remove_reference_t<decltype(*p)>
.
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