移动构造函数被逗号运算符抑制

时间:2012-09-05 19:05:52

标签: c++ c++11 return move-semantics comma-operator

这个程序:

#include <iostream>
struct T {
    T() {}
    T(const T &) { std::cout << "copy constructor "; }
    T(T &&) { std::cout << "move constructor "; }
};
int main() {
    ([](T t) -> T { return t; })({}); std::cout << '\n';
    ([](T t) -> T { return void(), t; })({}); std::cout << '\n';
    ([](T t) -> T { return void(), std::move(t); })({}); std::cout << '\n';
}

由gcc-4.7.1输出(link)编译时:

move constructor 
copy constructor 
move constructor 

为什么逗号运算符会产生这种效果?标准说:

  

5.18逗号运算符[expr.comma]

     

1 - [...]类型   结果的值是右操作数的类型和值;结果与右操作数[...]具有相同的值类别。如果右操作数的值是临时值,则结果是临时值。

我是否遗漏了允许逗号运算符影响程序语义的内容,或者这是gcc中的错误?

2 个答案:

答案 0 :(得分:14)

自动移动基于复制资格的资格:

§12.8 [class.copy] p32

  

当满足或将满足复制操作的省略标准时,除了源对象是函数参数,并且要复制的对象由左值指定,重载决策以选择构造函数首先执行复制,就好像对象是由右值指定的一样。 [...]

当返回表达式是自动对象的名称时,允许依次复制elision。

§12.8 [class.copy] p31

  

在具有类返回类型的函数中的return语句中,当表达式是非易失性自动对象的名称时(函数或catch-clause参数除外) )使用与函数返回类型相同的cv-unqualified类型,通过将自动对象直接构造为函数的返回值,可以省略复制/移动操作

插入逗号运算符后,表达式不再是自动对象的名称,而只是对一个表达式的引用,这会抑制复制省略。

答案 1 :(得分:8)

t 本地的命名变量,因此是左值。逗号运算符的行为与文档相同。

相反,你应该问为什么return t;允许t绑定到右值参考 - 是真正的魔法。