Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template argument deduction and expression rules

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&.

like image 446
Gabriel Avatar asked Oct 29 '25 13:10

Gabriel


1 Answers

  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.

like image 79
Oliv Avatar answered Nov 01 '25 02:11

Oliv