使用模板移动运算符

时间:2012-06-14 07:56:05

标签: c++ templates c++11 move-semantics

我有一个模板化的课程,我想避免复制(因为这样做的潜在成本)。我可以实现一个移动构造函数,但我还想允许移动“accross template parameter”。这是我正在尝试编译的内容:

template <class T>
class Foo
{
public:
    Foo() {}
    template <class U> Foo(Foo<U>&&) {}

private:
    Foo(const Foo&);
};

Foo<int> f() { Foo<float> y; return move(y); }
Foo<int> g() { Foo<int> x; return x; }
Foo<int> h() { Foo<float> z; return z; }

我理解为什么技术上f编译:移动类型(y)是Foo(浮动)&amp;&amp;并且碰巧有一个方便的构造函数接受Foo(U)&amp;&amp;,因此编译器设法找到U = float工作。

h无法编译。 z的类型为Foo(浮点数),我猜这离Foo(U)&amp;&amp;要弄清楚如果选择U = float就可以调用移动构造函数......

我不确定为什么g编译,但确实如此。 x的类型是Foo(int)。编译器如何设法使用move运算符(它不能只是从Foo(int)隐式转换为Foo(int)&amp;&amp;,可以吗?)

所以我的问题是:规则是什么?为什么h编译但g不?有什么我可以在Foo中改变以使其编译吗?

谢谢

1 个答案:

答案 0 :(得分:6)

复制或移动构造函数不能是模板。从12.8(2,3):

  

如果第一个参数类型为XX&const X&,则类volatile X&非模板构造函数是一个复制构造函数或const volatile X&,或者没有其他参数,或者所有其他参数都有默认参数(8.3.6)。 [示例:X::X(const X&)X::X(X&,int=1)是复制构造函数。]

     

X非模板构造函数是移动构造函数,如果其第一个参数类型为X&&const X&&volatile X&& ,或const volatile X&&,并且没有其他参数,或者所有其他参数都有默认参数(8.3.6)。 [示例:Y::Y(Y&&)是移动构造函数。]

因此,您的示例fg有效,因为您正在调用普通构造函数(而不是 move --constructor)。

f有明显原因,因为move(y)的结果可以绑定到Foo<float>&&g的作用原因不同:由于x的类型与函数的返回类型相同,因此返回语句中表达式x的值与{{1}匹配}。这是因为12.8(31,32):

  

在具有类返回类型的函数中的Foo<int>&&语句中,当表达式是非易失性自动对象的名称(除了函数或catch子句参数)具有相同的cv-unqualified type作为函数返回类型,[...]

     

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

最后,我们了解为什么return不起作用:h语句中的z表达式的值无法绑定到return,因为它不是Foo<float>&&显式转换(通过std::move),也没有给出第12.8(32)条的特殊规定,因为它的类型与函数的返回类型不同。 (它只能绑定到Foo<float>&(这几乎肯定是错误的)或Foo<float> const &。)


顺便说一句,没有必要移动不管理外部资源(例如图元)的对象。无论如何都必须复制实际的对象数据。