【发布时间】:2023-03-07 15:57:02
【问题描述】:
考虑以下几点:
struct my_type {};
my_type make_my_type() { return my_type{}; }
void func(my_type&& arg) {}
int main()
{
my_type&& ref = make_my_type();
func(ref);
}
不用说,这段代码无法编译。我意识到我需要在第二个函数调用中使用std::move(),但为了便于理解,我想按原样考虑代码。
尝试编译上述内容,Clang 3.5 告诉我:
错误:没有匹配的函数调用'func'
注意:候选函数不可行:对于第一个参数 void func(my_type&&) {}
,没有已知的从 'my_type' 到 'my_type &&' 的转换
虽然 g++ 4.9 说的几乎相同:
错误:无法将“my_type”左值绑定到“my_type&&”
注意:初始化 'void func(my_type&&)' 的参数 1
这些错误信息让我很困惑,因为虽然ref 肯定是一个左值,但它的type 仍然是my_type&&...不是吗?
我正试图准确了解这里发生了什么,所以我想知道以下哪些(如果有的话)是正确的:
-
由于只有右值可以绑定到右值引用,而
ref是左值,它不能绑定到arg。来自 Clang 和 g++ 的错误消息在声称ref是“无法转换”的(非参考)my_type时具有误导性。 -
因为它是一个左值,所以
ref被视为非引用my_type,尽管它的实际类型是my_type&&。来自 Clang 和 g++ 的错误消息具有误导性,因为它们显示的是内部用于函数匹配的类型,而不是ref的真实类型。 -
在
main()的主体中,ref的类型是普通的my_type,尽管我明确写了my_type&&。所以编译器的错误信息是准确的,我的期望是错误的。然而,情况似乎并非如此,因为static_assert(std::is_same<decltype(ref), my_type&&>::value, "");通过。
-
还有其他一些我没有考虑过的魔法。
重复一遍,我知道解决方案是使用std::move() 将rref 转换回rvalue;我正在寻找“幕后”发生的事情的解释。
【问题讨论】:
-
while ref is certainly an lvalue, its type is still my_type&&... isn't it?不是真的。对于大多数意图和目的,引用类型的表达式不存在。 "5/5 如果表达式最初具有类型“对 T 的引用”(8.3.2、8.5.3),则在进一步分析之前将类型调整为 T。表达式指定对象或由引用表示的函数,并且表达式是左值或 xvalue,具体取决于表达式。" -
我 认为 Nic's answer 对一个有点相关的问题可能会提供一两个提示。
-
嗯,作为参数传递给函数的是一个表达式,如
f(2+2)。表达式的一种可能形式是 id-expression (5.1.1) - 只是一个名称(变量或命名常量)。在func(ref)中,ref是一个 id-expression,其 unqualified-id 命名一个变量。变量类型为my_type&&;该表达式是my_type类型的左值,这要归功于每个5/5 的调整。 -
您的第一个要点是正确的。 表达式
ref的结果是一个左值。编译器语法也是正确的,不仅是因为上述原因,还因为没有“my_type&&lvalue”之类的东西。 -
使用
expression_name<decltype((ref))>()(stackoverflow.com/a/20721887/576911) 输出表达式ref的类型。使用type_name<decltype(ref)>()(stackoverflow.com/questions/81870/print-variable-type-in-c/…)输出ref的声明类型。
标签: c++ c++11 language-lawyer rvalue-reference pass-by-rvalue-reference