模板参数推导和表达式规则

Gab*_*iel 4 c++ templates language-lawyer c++20

我有一个关于这个问题的后续问题:符号PA参考temp.deduct.call部分 如果我正确理解模板参数推导,则以下代码会发生以下情况:

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

int b;
foo(std::move(b));
Run Code Online (Sandbox Code Playgroud)
  • 首先,编译器分别为参数声明和模板实参推导出两种类型P和。我们正在推论声明是引用(但不是转发引用)A的情况const T&
  • 对于A:std::move(b)类型为int&&[xvalue] -> 调整为A:= int( [7.2.2#1] )
  • 对于Pconst T&-> 删除 const 和引用 ([ 12.9.2.1#3 ]) ->P:= T
  • 模式匹配A- P > 结果T:= int

两个问题:

  1. 所描述的程序准确吗?
  2. std::move(b)是一个表达式,我一直认为它的类型是int&&(因为std::move返回 a int&&),但是 ( [7.2.2#1] ) 告诉了一些不同的事情,这意味着在进行任何分析之前删除每个引用,所以当人们谈论表达式的类型时,从来没有涉及任何参考:
struct A{ A& operator+(const A&);}
A a, b;
auto c = a + b;
Run Code Online (Sandbox Code Playgroud)

所以a+b显然返回一个A&. 但表达式的类型是A. 那是对的吗 ?declval(a+b)是另一只野兽,并返回A&

Oli*_*liv 5

  1. 所描述的程序是准确的。
  2. 该引用已从表达式类型中删除。但是表达式有另一个属性,value-category ,它映射到函数调用表达式[expr.call]/14 的引用类型:

    如果结果类型是左值引用类型或对函数类型的右值引用,则函数调用是左值;如果结果类型是对对象类型的右值引用,则函数调用是 xvalue;否则是纯右值。

这几乎可以用那些推理规则来表示:

function return type             function call expression [type,value-category]
     T&                  =>        [ T , lvalue ]
     T&&                 =>        [ T , xvalue ]
     T                   =>        [ T , prvalue ]
Run Code Online (Sandbox Code Playgroud)

decltype进行反向映射,[dcl.type.decltype]/1

对于表达式 e,decltype(e) 表示的类型定义如下:

  • [...]
  • 否则,如果 e 是 xvalue,则 decltype(e) 是 T&&,其中 T 是 e 的类型;

  • 否则,如果 e 是左值,则 decltype(e) 是 T&,其中 T 是 e 的类型;

  • 否则,decltype(e) 是 e 的类型。

因此,通过引用为类型带来的信息不会因删除 [expr.type] 中的引用而丢失。该信息由值类别表示。

  • @加布里埃尔。*id-expression* 始终是左值。表达式“a”的类型是“int”,值类别是“lvalue”。将变量声明类型的概念与仅作为该变量名称的表达式的类型分开是很重要的。也许这个问答会有所帮助:/sf/ask/3962178601/# 56602744 (2认同)