Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用模板移动运算符_C++_Templates_C++11_Move Semantics - Fatal编程技术网

C++ 使用模板移动运算符

C++ 使用模板移动运算符,c++,templates,c++11,move-semantics,C++,Templates,C++11,Move Semantics,我有一个模板化的类,我希望避免复制(因为这样做的潜在成本)。我可以实现一个移动构造函数,但我也希望允许移动“accross模板参数”。以下是我试图编译的内容: template <class T> class Foo { public: Foo() {} template <class U> Foo(Foo<U>&&) {} private: Foo(const Foo&); }; Foo<int>

我有一个模板化的类,我希望避免复制(因为这样做的潜在成本)。我可以实现一个移动构造函数,但我也希望允许移动“accross模板参数”。以下是我试图编译的内容:

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; }
模板
福班
{
公众:
Foo(){}
模板Foo(Foo&&{}
私人:
富(常富&);
};
Foo f(){Foo y;返回移动(y);}
Foo g(){Foo x;返回x;}
fooh(){fooz;返回z;}
我理解f编译的技术原因:move(y)的类型是Foo(float)&&并且碰巧有一个方便的构造函数,它接受Foo(U)&&,因此编译器设法发现U=float是有效的

h不编译。z是Foo(float)类型,我想这离Foo(U)太远了&如果选择了U=float,那么move构造函数就可以被调用了

我不知道g为什么编译,但它确实编译。x的类型是Foo(int)。编译器如何使用move操作符(它不能只是从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&
g
工作的原因不同:由于
x
的类型与函数的返回类型相同,因此return语句中表达式
x
的值与
Foo&
匹配。这是因为12.8(31,32):

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

当满足或将满足省略复制操作的条件时,除非源对象是函数参数,并且要复制的对象由左值指定,否则将首先执行重载解析以选择复制的构造函数,就像对象由右值指定一样

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



顺便说一下,移动不管理外部资源的对象(例如原语)是没有意义的。无论如何都必须复制实际的对象数据。

@anonymous:Hm,你说得对,你有一个用户定义的构造函数。@anonymous:Your
g
实际上正在使用模板。我现在找到了真正的原因;编辑,谢谢!这是有道理的。我能做些什么让h编译并使用移动语义吗?@anonymous:像你在
f
中那样说
std::move
有什么不对?这看起来是最直接的解决方案。我确实想提供一个从Foo(U)到Foo(T)的复制构造函数,它将使h编译,但不使用move操作符。我非常确信,我的类中没有任何用户会检查他们正在使用的运算符,如果他们编写的代码看起来像h,这意味着他们最终会调用更昂贵的复制构造函数……我只是试着用MSVC、Clang和GCC来编译它——所有这三个函数都是编译的。