我有一个关于这个 one 的后续问题:
符号 P
和 A
引用 temp.deduct.call 部分
如果我正确理解模板参数推导,下面的代码会发生以下情况:
template<typename T>
void foo(const T& a);
int b;
foo(std::move(b));
- 首先编译器推导出两种类型
P
和A
分别用于参数声明和模板实参。我们正在推断声明是引用const T&
(但不是转发引用) 的情况
- 对于
A
:std::move(b)
具有类型int&&
[xvalue] -> 调整为A := 整数
( [7.2.2#1] ) - 对于
P
:const T&
-> 移除 const 和引用 ([ 12.9.2.1#3 ]) ->P:= T
< - 模式匹配
A
与P
-> 结果T:= int
。
两个问题:
- 所描述的程序准确吗?
std::move(b)
是一个表达式,我一直认为它的类型是int&&
(因为std::move
返回一个int&&
),但是 ( [7.2.2#1] ) 说明了一些不同的东西,这意味着在进行任何分析之前删除所有引用,因此当谈论表达式的类型时,永远不会涉及任何引用:
struct A{ A& operator+(const A&);}
A a, b;
auto c = a + b;
所以a+b
显然返回了一个A&
。但表达式的类型是 A
。那是对的吗 ? declval(a+b)
是另一个怪兽,返回 A&
。
最佳答案
- 所描述的程序是准确的。
引用已从表达式类型中删除。但是表达式获得另一个属性,值类别,它映射到函数调用表达式的引用类型 [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.
这几乎可以用那些推理规则来表示:
function return type function call expression [type,value-category]
T& => [ T , lvalue ]
T&& => [ T , xvalue ]
T => [ T , prvalue ]
decltype
做反向映射,[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.
因此,引用带给类型的信息不会因删除 [expr.type] 中的引用而丢失。此信息由值类别表示。
关于c++ - 模板参数推导和表达式规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56627124/