1

I'm reading about decltype with multiple arguments and according to everyone else it just validates that all types are consistent and if so, completely discards all parameters but the last one. However it seems that passing another parameter does affect the return value:

  int i = 7;
  decltype(i) var = i;
  ++var;
  cout << i << endl; // prints '7', as I would expect

but:

  int i = 7;
  decltype(1, i) var = i;
  ++var;
  cout << i << endl; // prints '8' - apparently 'var' is now a reference to 'i'

Why is that?

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
Valentin
  • 1,108
  • 8
  • 18
  • 1
    `according to everyone else it just validates that all types are consistent and if so, completely discards all parameters but the last one` What is the source? I've never seen anyone claiming that before. – cpplearner Feb 23 '17 at 02:32
  • For instance, if I understood it correctly, here: http://stackoverflow.com/questions/16044514/what-is-decltype-with-two-arguments?rq=1. "A pair of expressions separated by a comma is evaluated left-to-right; the left expression is a discarded-value expression", "the result is of the same value category as its right operand" – Valentin Feb 23 '17 at 02:36
  • Try `decltype((i))` – Richard Critten Feb 23 '17 at 02:50
  • with `decltype((i))` it prints '8' in both cases.. So why is `decltype(i)` different from everything else? Or, in other words: why do `decltype(i)` and `decltype((i))` behave differently, but `decltype(i, j)` and `decltype((i, j))` behave the same? – Valentin Feb 23 '17 at 02:54

3 Answers3

4

decltype does not take multiple arguments. You have passed it a single argument that happens to be a comma expression. If the last argument of the comma expression is just a variable, rather than introducing a temporary, the expression as a whole evaluates to a reference.

You can see the same thing without decltype:

#include <iostream>

int main(void) {
  int i = 5;
  (1, i) = 10;
  std::cout << i << std::endl;
}
Azure
  • 251
  • 1
  • 4
3

You are looking at , which is an operator in C++ (comma operator). See row 16

Its declaration may looks like this: T2& operator,(const T& a, T2& b);

So a, b, c is evaluate as ((a,b),c), (b,c), (c), which returns a reference to the return type of c (a, b, c can be expressions)

In your case 1, i returns a reference to the last term, i. Hence the type is int&, so decltype(1, i) var = i; becomes int& var = i;

(i) is an expression, and it has return value which is a reference to i (int&)

tnt
  • 1,174
  • 2
  • 10
  • 14
3

When decltype's argument is an immediate identifier (or class member access), it is treated in a special way - it denotes the exact declared type of the argument.

Otherwise, the argument of decltype is treated as an expression. It resolves to the type of that expression adjusted in accordance with the value category of that expression. E.g. if the expression is an lvalue, the type denoted by such decltype is a reference type.

In your case decltype(i) falls into the first category. So decltype(i) stands for int, since i is declared as an int.

Meanwhile your decltype(1, i) does not fit the first category. Its argument is treated as expression 1, i. Since in C++ the result of such application of comma operator is an lvalue, this decltype denotes type int &.

For another example, decltype((i)) would not fit the first category either because of the extra (). Since expression (i) is an lvalue, decltype((i)) denotes type int &.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765