Dou*_*oug 14 c++ temporary rvalue-reference c++11
(我在comp.std.c ++上询问了这个问题的变体,但没有得到答案.)
为什么f(arg)
在这段代码中的调用调用const ref重载f
?
void f(const std::string &); //less efficient
void f(std::string &&); //more efficient
void g(const char * arg)
{
f(arg);
}
Run Code Online (Sandbox Code Playgroud)
我的直觉说f(string &&)
应该选择重载,因为arg
无论如何都需要转换为临时值,并且临时匹配rvalue引用比lvalue引用更好.
这不是GCC和 MSVC中发生的事情(编辑:谢谢Sumant:它不会发生在GCC 4.3-4.5中).至少在G ++和 MSVC中,任何左值都不会绑定到右值引用参数,即使创建了一个中间临时值.实际上,如果不存在const ref重载,编译器会诊断出错误.然而,编写f(arg + 0)
或f(std::string(arg))
不选择右值引用过载如你所愿.
从我对C++ 0x标准的阅读中,似乎在考虑是否f(string &&)
可行时应考虑将const char*隐式转换为字符串,就像传递const lvalue ref参数时一样.第13.3节(重载解析)在很多地方没有区分rvalue refs和const引用.此外,似乎阻止左值绑定到右值引用(13.3.3.1.4/3)的规则不适用,如果存在中间临时值 - 毕竟,从临时值移动是完全安全的.
这是:
编辑:我有一个相关的后续问题:C++ 0x rvalue引用 - lvalues-rvalue绑定
海湾合作委员会根据FCD做错了.FCD在8.5.3
参考绑定方面说
您调用std::string &&
匹配项的情况都不是,因为初始化程序是左值.它没有到达创建临时右值的地方,因为顶级子弹已经需要一个右值.
现在,重载决策不直接使用引用绑定来查看是否存在隐式转换序列.相反,它说13.3.3.1.4/2
当引用类型的参数不直接绑定到参数表达式时,转换序列是根据13.3.3.1将参数表达式转换为引用的基础类型所需的转换序列.
因此,即使获胜者实际上无法绑定到该参数,重载决策也会成为赢家.例如:
struct B { B(int) { /* ... */ } };
struct A { int bits: 1; };
void f(int&);
void f(B);
int main() { A a; f(a.bits); }
Run Code Online (Sandbox Code Playgroud)
8.5
禁止位域的引用绑定绑定到左值引用.但是重载决策表明转换序列是转换到的序列int
,因此即使稍后调用时,调用也是成功的.因此,我的位域示例是不正确的.如果是选择B
版本,它会成功,但需要用户定义的转换.
但是,该规则存在两个例外.这些是
除了隐式对象参数(参见13.3.1)之外,如果需要将非const的左值引用绑定到rvalue或将rvalue引用绑定到左值,则无法形成标准转换序列.
因此,以下调用有效:
struct B { B(int) { /* ... */ } };
struct A { int bits: 1; };
void f(int&); /* binding an lvalue ref to non-const to rvalue! */
void f(B);
int main() { A a; f(1); }
Run Code Online (Sandbox Code Playgroud)
因此,您的示例调用该const T&
版本
void f(const std::string &);
void f(std::string &&); // would bind to lvalue!
void g(const char * arg) { f(arg); }
Run Code Online (Sandbox Code Playgroud)
但是,如果你说f(arg + 0)
,你创建一个右值,因此第二个函数是可行的.
这是您阅读的标准草案中的缺陷.出于安全原因,这种缺陷作为一些急切编辑的副作用而不允许将左值引用绑定到左值.
你的直觉是正确的.当然,即使初始化程序是左值表达式,允许rvalue引用引用一些未命名的临时也没有什么坏处.毕竟,这是rvalue引用的用途.您观察到的问题已于去年修复.即将推出的标准将强制要求在您的示例中选择第二个重载,其中rvalue引用将引用一些临时字符串对象.
规则修正案进入了草案n3225.pdf(2010-11-27):
- [...]
- 否则,引用应是对非易失性const类型的左值引用(即,cv1应为const),或者引用应为rvalue引用
,初始化表达式应为rvalue或具有函数类型.[...]
- [...]
- 否则,会创建临时的[...] [...]
double&& rrd3 = i; // rrd3 refers to temporary with value 2.0
Run Code Online (Sandbox Code Playgroud)
但N3225似乎错过了说i
这个例子中的内容.最新的N3290草案包含以下示例:
double d2 = 1.0;
double&& rrd2 = d2; // error: copying lvalue of related type
int i3 = 2;
double&& rrd3 = i3; // rrd3 refers to temporary with value 2.0
Run Code Online (Sandbox Code Playgroud)
由于您的MSVC版本在此问题得到修复之前发布,因此它仍然根据旧规则处理rvalue引用.预计下一个MSVC版本将实现新的右值引用规则(被MSVC开发人员称为"rvalue references 2.1"),请参阅链接.