Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type of (x) in C++ [duplicate]

Given:

decltype(auto) f1()
{
    int x = 0;
    return x;  // decltype(x) is int, so f1 returns int
}
decltype(auto) f2()
{
    int x = 0;
    return (x);  // decltype((x)) is int&, so f2 returns int&
}

(Taken from Scott Meyer's Effective Modern C++).

Now, if I have found the correct paragraph, Section 7.1.5.2 Simple type specifiers [dcl.type.simple] of the C++ standard says:

If e is an id-expression or a class member access (5.2.5 [expr.ref]), decltype(e) is defined as the type of the entity named by e

and the example from that section is:

struct A { double x; }

const A* a = new A();

decltype((a->x)); // type is const double&

Now, I wonder why is the decltype((x)) is deduced to be int& in the book.

like image 377
Ferenc Deak Avatar asked Nov 02 '15 14:11

Ferenc Deak


3 Answers

The relevant standards quote is:

N4140 [dcl.type.simple]/4: For an expression e, 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 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.

Since x is an lvalue, and the expression is parenthesized, the third rule is used, so decltype((x)) is int&.

like image 116
TartanLlama Avatar answered Nov 14 '22 19:11

TartanLlama


decltype returns the declared type of a variable, or the "type" of an expression (with some reference added to indicate l/r valueness).

This lets it be used for two different purposes. Sometimes this causes confusion, but it is what it is.

The token x is a variable. The type of the variable is int.

The tokens (x) are not a variable, but rather a (really trivial) expression containing nothing but one variable. As such, the type of the expression (as determined by decltype) (x) is int&.

The type of the expression x (if you could convince decltype to give it to you; you cannot) is also int&, but the rule that the decltype(ACTUAL_VAR_NAME) evaluates to the type of the variable "wins".

Now, none of the above is true. The actual truth is a quote of the standard which describes the steps that a compiler is supposed to go through to determine what type decltype returns. But it is an effective lie, and one (if the standard wording turned out to have errors) that might indicate the standard has a bug when it disagrees with it.

like image 8
Yakk - Adam Nevraumont Avatar answered Nov 14 '22 17:11

Yakk - Adam Nevraumont


§ 7.1.6.4 [dcl.spec.auto] (draft n3797)

  1. ... If the placeholder is the decltype(auto) type-specifier , the declared type of the variable or return type of the function shall be the placeholder alone. The type deduced for the variable or return type is determined as described in 7.1.6.2 , as though the initializer had been the operand of the decltype .

§ 7.1.6.2 [dcl.type.simple]

  1. For an expression e , 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 by e . If there is no such entity, or if e names a set of overloaded func- tions, 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

x is is an unparenthesized id-expression and therefore the return type is deduced as the type of x: int

(x) is not an unparenthesized id-expression so that rule does not apply. However, it is a (parenthesized) lvalue expression. Therefore the deduced type is T& where T is the type of x: int&

like image 5
eerorika Avatar answered Nov 14 '22 19:11

eerorika