4

I have a following up question regarding this one: Notation P and A refer to the section temp.deduct.call If I understand template argument deduction correctly, the following happens for the code below:

template<typename T>
void foo(const T& a);

int b;
foo(std::move(b));
  • First the compiler deduces two types P and A for the parameter declaration and the template argument, respectively. We are deducing for the case when the declaration is a reference const T& (but not a forwarding reference)
  • For A: std::move(b) has type int&& [xvalue] -> which is adjusted to A:= int ([7.2.2#1])
  • For P: const T& -> remove const and reference ([12.9.2.1#3]) -> P:= T
  • Pattern Match A against P -> Result T:= int.

Two Questions:

  1. Is that described procedure accurate?
  2. std::move(b) is an expression and I always thought its type is int&& (because std::move returns a int&&), but ([7.2.2#1]) tells something different, meaning removing every reference before any analysis happens, so when one talks about the type of an expression, there is never any reference involved:
struct A{ A& operator+(const A&);}
A a, b;
auto c = a + b;

So a+b clearly returns a A&. but the type of the expression is A. Is that correct ? declval(a+b) is another beast, and returns A&.

Max Langhof
  • 23,383
  • 5
  • 39
  • 72
Gabriel
  • 8,990
  • 6
  • 57
  • 101
  • 1
    `A& operator+(const A&);` looks very curious. Not necessarily illegal but certainly very odd. Not that it matters for your question. – Max Langhof Jun 17 '19 at 08:16
  • I know, its not very good to return a reference, its plain wrong, but only serves as an example to demonstrate my point. :) – Gabriel Jun 17 '19 at 08:21
  • 1
    [This Q](https://stackoverflow.com/questions/17241614/what-expressions-yield-a-reference-type-when-decltype-is-applied-to-them) has some information on how expressions of references work. `declval(...)` does not return a reference type for the same reason. – Rakete1111 Jun 17 '19 at 08:34

1 Answers1

5
  1. That described procedure is accurate.
  2. The reference is removed from an expression type. But an expression get another property, the value-category, which is mapped to the kind of reference for function call expressions [expr.call]/14:

    A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.

This can almost be represented by those rules of inferences:

function return type             function call expression [type,value-category]
     T&                  =>        [ T , lvalue ]
     T&&                 =>        [ T , xvalue ]
     T                   =>        [ T , prvalue ]

decltype do the reverse mapping, [dcl.type.decltype]/1:

For an expression e, the type denoted by decltype(e) is defined as follows:

  • [...]
  • 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.

So the information that is brought to a type by the reference is not lost by the removal of the reference in [expr.type]. This information is represented by the value-category.

Oliv
  • 17,610
  • 1
  • 29
  • 72
  • What still puzzles me is: `int&& a; a;` whats the type of the expression `a;`. Is it a `id-expression` and its type is `int&&` ? – Gabriel Jun 17 '19 at 11:30
  • @Gabriel, The type of `a` is exactly as specified in its declaration: `int&&`. (Its value category is lvalue.) – chris Jun 17 '19 at 11:50
  • 2
    @Gabriel. *id-expression* are always lvalues. The type of the expression `a` is `int` and the value category is `lvalue`. It is important to dissociate the concept of the declared type of a variable and the type of the expression that is just the name of that variable. Maybe this Q&A will help: https://stackoverflow.com/questions/56602551/when-a-function-takes-an-rvalue-reference-what-is-the-type-of-that-variable-wit/56602744#56602744 – Oliv Jun 17 '19 at 12:01
  • So you basically refering to [dcl.type.decltype.1.3](https://timsong-cpp.github.io/cppwp/dcl.type.decltype#1.3) for `decltype(a)`. Is that correct? – Gabriel Jun 17 '19 at 12:27
  • @Gabriel Indeed `decltype(a)` gives the declared type of the variable `a`. In `decltype(a)`, `a` is not considered as an id-expression. The fact that an id-expression is an lvalue can be seen with `decltype((a))` which is `int &`. – Oliv Jun 17 '19 at 14:09
  • You are saying: in `decltype(a)` , `a` is not considered an `id-expression`, then I am wondering which case in [https://timsong-cpp.github.io/cppwp/dcl.type.decltype] is happening, because it can only be 1.3 otherwise this case is denoted somewhere else in the standard?? – Gabriel Jun 18 '19 at 07:16
  • @Oliv Also [Link](https://stackoverflow.com/questions/17241614/what-expressions-yield-a-reference-type-when-decltype-is-applied-to-them) tells something different. And actually manifests my point of rule 1.3 taking place. – Gabriel Jun 18 '19 at 07:57
  • 1
    @Gabriel I meant `decltype(a)` does not provides you information about the type and value category of the id-expression `a`, but about the type of the variable that is denoted by the id-expression `a` (the declared type of `a`). – Oliv Jun 18 '19 at 15:52