模板构造函数无法选择?

时间:2014-03-04 06:43:45

标签: c++ templates constructor language-lawyer

template <typename T>
class A {
public:
    template<class C> A(const A<C>&) {}
    A(A&&) {}
};

void f(A<int>& a)
{
    A<int> b(a);
}

以上代码无法在g ++ / clang ++中编译报告复制构造函数因用户提供的移动构造函数而被删除(尽管vc ++编译正常)。是否有任何标准要求阻止在重载解析期间选择模板构造函数(我知道它不是复制构造函数)?或者是否要求初始化程序与initializee具有相同的类型时,必须选择复制构造函数?

1 个答案:

答案 0 :(得分:4)

注意; gccclang在尝试编译提供的代码段时显示正确的行为。


为什么vc++错误接受该片段?

  1. 函数模板永远不会以产生复制构造函数的方式实例化,因为可以在c ++标准的以下两个引号中读取:

      

    [<强> class.copy

         

    2)类X的非模板构造函数是复制构造函数,如果其第一个参数的类型为X&,{{1 }},const X&volatile X& ,并且没有其他参数,或者所有其他参数都有默认参数(8.3.6)。

         

    ...

         

    6)类const volatile X&的构造函数声明如果其第一个参数是类型(可选择cv-qualified)X并且没有其他参数或其他所有其他参数,则格式错误参数有默认参数。 永远不会实例化成员函数模板以生成此类构造函数签名。

  2. 如果显式声明 move-constructor ,则隐式生成的 copy-constructor 将不可调用,请参阅以下内容:

      

    [<强> class.copy

         

    7)如果类定义没有显式声明复制构造函数,则会声明隐式如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数被定义为已删除;否则,它被定义为默认(8.4)


  3. X

    考虑到前面提到的c ++标准的引用,我们可以很容易地看到struct Obj { template<typename T> Obj (T const&) { } Obj (Obj&&) { } }; ... Obj a; Obj b (a); 的上述定义在语义上等同于下面,因为我们显式声明的 move-constructor 将使我们隐式声明的复制构造函数Obj

    = delete;

    根据重载决议的规则,删除的功能在尝试找到最佳匹配时仍然参与,但如果他们赢得了最佳匹配的战斗,则该程序是不正确的。这正是代码片段中发生的事情。

    struct Obj { template<typename T> Obj (T const&) { } Obj (Obj const&) = delete; Obj (Obj&&) { } }; Obj (Obj const&) = delete更合适,但由于复制构造函数不可调用,因此代码段无法编译。