C++为什么将左值传递给移动构造函数适用于模板?

bit*_*ise 6 c++ templates c++11 visual-studio-2012

我有这个代码,它不编译,这是预期的.

这是错误:an rvalue reference cannot be bound to an lvalue

class SomeData
{
public:
    vector<int> data;

    SomeData()
    {
        cout << "SomeData ctor" << endl;
        data.push_back(1);
        data.push_back(2);
        data.push_back(3);
    }

    SomeData(const SomeData &other)
    {
        cout << "SomeData copy ctor" << endl;
        data = other.data;
    }

    SomeData(SomeData &&other)
    {
        cout << "SomeData move ctor" << endl;
        data = move(other.data);
    }

    ~SomeData()
    {
        cout << "SomeData dtor" << endl;
    }

    void Print() const
    {
        for(int i : data)
            cout << i;

        cout << endl;
    }
};

void Function(SomeData &&someData)
{
    SomeData localData(someData);
    localData.Print();
}

int main(int argc, char *argv[])
{
    SomeData data;
    Function(data);                       // ERROR

    data.Print();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是,当我Function()变成一个模板时,它工作正常,并使用复制构造函数SomeData.

template<class T>
void Function(T &&someData)
{
    T localData(someData);                  // no more error
    localData.Print();
}
Run Code Online (Sandbox Code Playgroud)


这是标准的C++行为吗?

我注意到视觉工作室在模板方面往往更宽容,所以我想知道我是否可以从所有兼容的C++ 11编译器中获得相同的行为.

jog*_*pan 9

是.在模板函数的情况下,编译器推导出模板参数T,使其与给定的参数匹配.

因为someData实际上是左值,T所以推断为SomeData &.Function类型扣除后的声明然后变成

void Function(SomeData & &&)
Run Code Online (Sandbox Code Playgroud)

并且SomeData & &&,遵循参考折叠规则,变为SomeData &.

因此,函数参数someData变为左值引用,并且这样传递给初始化localData.请注意(正如@aschepler正确指出的那样)localData被声明为T,因此它本身就是类型的引用SomeData &.因此,这里没有复制构造 - 只是初始化引用.


如果你想localData成为一个真正的副本,你必须将类型SomeData &转换为SomeData,即你必须&从类型中删除.你可以这样做std::remove_reference:

template<class T>
void Function(T &&someData)
{
   /* Create a copy, rather than initialize a reference: */
    typename std::remove_reference<T>::type localData(someData);
    localData.Print();
}
Run Code Online (Sandbox Code Playgroud)

(为此,你必须这样做#include <type_traits>.)

  • 这实际上是*预期和良好的*行为和*完美转发*的基础. (2认同)