模板“复制构造函数”不会阻止编译器生成的移动构造函数

Mar*_*tin 1 c++ c++11

考虑以下程序及其中的注释:

template<class T>
struct S_ {
    S_() = default;

    // The template version does not forbid the compiler
    // to generate the move constructor implicitly
    template<class U> S_(const S_<U>&) = delete;

    // If I make the "real" copy constructor
    // user-defined (by deleting it), then the move
    // constructor is NOT implicitly generated
    // S_(const S_&) = delete;
};

using S = S_<int>;

int main() {
    S s;
    S x{static_cast<S&&>(s)};
}
Run Code Online (Sandbox Code Playgroud)

问题是:为什么用户自定义模板构造函数(当U = T时有效地充当副本构造函数)阻止了编译器生成move构造函数,相反,如果我定义了“真实”副本,构造函数(通过删除它),那么move构造函数不是隐式生成的(程序无法编译)吗?(可能的原因是,当T = U?时,“模板版本”也不遵守复制构造函数的标准定义。)

好消息是,这显然是我想要的。实际上,我需要编译器将隐式生成的所有复制和移动构造函数以及 所有移动和复制赋值运算符,就好像简单地将S定义为template<class U> S{};plus以及从other进行转换的模板构造函数一样S<U>。按照标准,我可以依靠S的上述定义来获得我需要的所有上述内容吗?如果是,那么我可以避免明确地“默认”它们。

小智 5

答案很简单-没有(!)模板副本构造函数。即使template参数与复制构造函数的参数匹配,它也不是复制构造函数。

请参见12.8复制和移动类对象

如果类X的非模板构造函数的第一个参数是X&,const X&,volatile X&或const volatile X&类型,并且没有其他参数,或者所有其他参数都具有默认参数(8.3.6),则它是副本构造函数。 )。[示例:X :: X(const X&)和X :: X(X&,int = 1)是副本构造函数。

类似的适用于move构造函数