为什么在C++ 0x中,编译器会选择特定的一般移动分配?

axi*_*mar 3 templates variable-assignment c++11

我有以下代码:

#include <iostream>
using namespace std;

template <class T> class Foo {
public:
    template <class U> void operator = (const U &u) {
        cout << "generic copy assigment\n";
    }

    void operator = (const Foo<T> &f) {
        cout << "specific copy assigment\n";
    }

    template <class U> void operator = (U &&u) {
        cout << "generic move assigment\n";
    }

    void operator = (Foo<T> &&f) {
        cout << "specific move assigment\n";
    }
};

int main() {
    Foo<int> i, j;
    i = j;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果运行,它会打印"通用移动分配",即编译器更喜欢移动副本.但是,如果我注释掉两个移动作业:

template <class T> class Foo {
public:
    template <class U> void operator = (const U &u) {
        cout << "generic copy assigment\n";
    }

    void operator = (const Foo<T> &f) {
        cout << "specific copy assigment\n";
    }
};
Run Code Online (Sandbox Code Playgroud)

输出是"特定的拷贝分配".

换句话说,当类启用移动时,将选择通用移动而不是特定移动,而如果类不启用移动,则选择特定副本而不是通用移动.

它是Visual Studio 2010的错误还是在c ++ 0x规范中定义的这种行为?

Joh*_*itb 5

您的模板不是"通用移动任务".但它是一个"完美的货运代理",除了在你的情况下它不转发.C++ 0x中的规则是模板参数推导特别处理参数"T &&":左值参数推导TArgType&,而Rvalue参数推导为ArgType.这样,类型的左值ArgType将产生最终参数类型ArgType&,并且Rvalue最终将屈服于ArgType&&.

在您的情况下,左值右侧产生一个推导出的参数类型"Foo&",它与lvalue参数完全匹配.

但是,当前草案(n3126)禁止编译器使用模板执行复制分配(在一个非常容易混淆的措辞中).它取决于问题1080的解决方案是否会改变.