使用模板移动运算符
Move operator with templates
我有一个模板化类,我想避免复制(因为这样做的潜在成本)。我可以实现一个移动构造函数,但我也想允许"跨模板参数"移动。这是我正在尝试编译的内容:
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编译:move(y)的类型是Foo(float)&&&,并且恰好有一个方便的构造函数需要Foo(U)&&,所以编译器设法找到U=float工作。
z 是 Foo(float) 的类型,我想这与 Foo(U)&&&相去甚远,无法弄清楚如果选择 U=float,则可以调用移动构造函数......
我不确定为什么 g 编译,但它确实如此。x 的类型是 Foo(int)。编译器如何设法使用移动运算符(它不能只是从 Foo(int) 隐式转换为 Foo(int)&&,不是吗?
所以我的问题是:规则是什么? 为什么 h 可以编译,而 g 不会? 我可以在 Foo 中更改一些东西来使 h 编译吗?
谢谢
复制或移动构造函数不能是模板。从 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)
是复制构造函数。类
X
的非模板构造函数是移动构造函数,如果它的第一个参数是X&&
、const X&&
、volatile X&&
或const volatile X&&
的类型,并且没有其他参数,或者所有其他参数都有默认参数 (8.3.6)。[示例:Y::Y(Y&&)
是一个移动构造函数。
因此,您的示例f
并且g
工作,因为您正在调用普通构造函数(而不是移动构造函数)。
f
工作的原因很明显,因为move(y)
的结果可以绑定到Foo<float>&&
。 g
工作的原因不同:由于x
的类型与函数的返回类型相同,因此 return 语句中表达式x
的值与Foo<int>&&
匹配。这是因为 12.8(31, 32):
在具有类返回类型的函数的
return
语句中,当表达式是与函数返回类型具有相同 CV 非限定类型的非易失性自动对象(函数或 catch 子句参数除外)的名称时,[...]当满足或将满足复制操作省略的条件(源对象是函数参数,并且要复制的对象由左值指定)时,首先执行重载解析以选择复制的构造函数,就像对象由右值指定一样。
最后,我们明白为什么h
不起作用:return
语句中表达式z
的值不能绑定到Foo<float>&&
,因为它没有显式强制转换(通过std::move
),也没有给出条款12.8(32)的特殊分配,因为它的类型与函数的返回类型不同。 (它只能绑定到Foo<float>&
(这几乎肯定是错误的)或Foo<float> const &
。
顺便说一下,移动不管理外部资源的对象(例如基元)是没有意义的。无论如何,必须复制实际的对象数据。
- 自定义先决条件对移动分配运算符有效吗
- 移动赋值运算符;尝试引用已删除的函数.我该如何解决这个问题?
- C++ - 没有自定义交换功能的移动分配运算符?
- 强制复制分配超过移动分配运算符
- 编译器调用复制运算符而不是移动运算符
- 对 r 值使用移动赋值运算符时的异常
- 移动语义和运算符 + 重载
- 运算符+ 的规范实现涉及额外的移动构造函数
- 在之后仍需要使用源对象时调用父移动分配运算符
- 删除复制构造函数是否也会删除默认的复制/移动运算符?
- 如何在COUT语句中使用移动运算符
- 为什么移动运算符不只是析构函数+移动构造函数
- VC2013 移动运算符不递归执行移动
- 使用模板移动运算符
- C++ - 组合复制/移动运算符和构造函数
- 在 C++11 中编写复制/移动/运算符 = 三重奏的"correct"方法是什么?
- 在赋值移动运算符内部使用交换
- 在移动运算符/赋值运算符中,我应该使用std::move还是std::forward
- 我应该在什么条件下考虑实现移动构造函数和移动运算符
- c++移动运算符类成员