使用模板移动运算符 [英] Move operator with templates

查看:129
本文介绍了使用模板移动运算符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个模板类,我想避免复制(因为这样做的潜在成本)。我可以实现一个移动构造函数,但我也想允许移动accross模板参数。这里是我想要编译:

I have a templated class that I want to avoid copying (because of the potential cost to do so). I can implement a move constructor, but I would also like to allow moving "accross template parameter". Here is what I'm trying to compile:

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 compiles:move(y)的类型是Foo ;&并且恰巧有一个方便的构造函数需要一个Foo(U)& amp;& amp;& amp;,所以编译器设法找到U = float works。

I understand why technically f compiles: the type of move(y) is Foo(float)&& and there happens to be a handy constructor that takes a Foo(U)&&, so the compiler manages to find that U=float works.

h doesn' t编译。 z的类型是Foo(float),我猜这距离Foo(U)&&如果U = float被选择,移动构造函数可以被调用...

h doesn't compile. z is of type Foo(float) and I guess that's too far from Foo(U)&& to figure out that the move constructor can be invoked if U=float is chosen...

我不知道为什么g编译,但它是。 x的类型是Foo(int)。编译器如何使用move操作符(它不能只是从Foo(int)到Foo(int)&& amp;& amp;的隐式转换,可以吗?)

I'm not sure why g compiles, but it does. The type of x is Foo(int). How does the compiler manage to use the move operator (it can't just implicit cast from Foo(int) to Foo(int)&&, can it?)

所以我的问题是:什么是规则?为什么h编译,但g不?

So my questions are: what are the rules? why does h compiles but g doesnt? is there something I can change in Foo to make h compile?

谢谢

推荐答案

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

A copy or move constructor mustn't be a template. From 12.8(2, 3):


非模板 X 是一个复制构造函数,如果它的第一个参数是 X& const X& volatile X& const volatile X& ,并且没有其他参数,默认参数(8.3.6)。 [示例: X :: X(const X&) X :: X(X&,int = 1)

A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments (8.3.6). [Example: X::X(const X&) and X::X(X&,int=1) are copy constructors.]

X 非模板构造函数如果其第一个参数是 X&&& const X&&&&< / code>, volatile X&&& const volatile X&&& ,并且没有其他参数,默认参数(8.3.6)。 [示例: Y :: Y(Y&&)是移动构造函数。]

A non-template constructor for class X is a move constructor if its first parameter is of type X&&, const X&&, volatile X&&, or const volatile X&&, and either there are no other parameters or else all other parameters have default arguments (8.3.6). [Example: Y::Y(Y&&) is a move constructor.]

所以你的例子 f g 工作,因为你正在调用一个普通的构造函数em> move -constructor)。

So your example f and g work because you're invoking an ordinary constructor (not a move-constructor).

f code> move(y)可以绑定到 Foo< float>&& g 原因不同:由于 x 的类型与函数的返回类型相同, return语句中的表达式 x 的值与 Foo< int>&& 匹配。这是因为在 return 语句中有12.8(31,32):

f works for obvious reasons, because the result of move(y) can bind to Foo<float>&&. g works for a different reason: Since the type of x is the same as the return type of the function, the value of the expression x in the return statement matches Foo<int>&&. This is because of 12.8(31, 32):


<在具有类返回类型的函数中,当表达式是具有与函数返回类型相同的cv非限定类型的非易失性自动对象(除函数或catch子句参数之外)的名称,[...]

in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, [...]

当满足复制操作的限制条件时,除非源对象是函数参数,并且要复制的对象由左值指定,则重载分辨率选择用于复制的构造函数首先被执行,就好像对象由右值指定。

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.

最后,我们看到为什么 h 不起作用:表达式 z return 语句不能绑定到 Foo< float>&&& ,因为它没有显式强制转换 std :: move ),也没有给出12.8(32)的特殊分配,因为它的类型与函数的返回类型不一样。 (它只能绑定到 Foo & (几乎肯定是错误的)或 Foo< float> const& code>。)

Finally we see why h doesn't work: The value of the expression z in the return statement cannot bind to Foo<float>&&, because it is not explicitly cast (via std::move), nor given the special dispensation of clause 12.8(32), since its type is not the same as the function's return type. (It can only bind to Foo<float>& (which would almost surely be wrong) or to Foo<float> const &.)


顺便说一下,不管理外部资源(例如原语)。实际的对象数据必须被复制。

By the way, there's no point moving objects that don't manage external resources (e.g. primitives). The actual object data has to be copied anyway.

这篇关于使用模板移动运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆