【问题标题】:template constructor cannot be selected? [duplicate]无法选择模板构造函数? [复制]
【发布时间】:2014-04-05 13:33:52
【问题描述】:
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++ 编译正常)。是否有任何标准要求阻止在重载解析期间选择模板构造函数(但我知道它不是复制构造函数)?或者有没有要求当initializer和initializee的类型相同时,必须选择一个拷贝构造函数?

【问题讨论】:

  • A(A&amp;&amp;) {}我觉得应该有单&amp;
  • @juanchopanza:谢谢!这消除了我的疑问。
  • @ShashwatKumar:不,问题的关键在于声明移动构造函数 (&amp;&amp;) 会删除复制构造函数。声明一个复制构造函数(&amp;,通常带有const)显然不会。

标签: c++ templates constructor language-lawyer


【解决方案1】:

注意;gccclang 在尝试编译提供的 sn-p 时显示正确的行为。


为什么vc++ 接受sn-p 是错误的?

  1. 函数模板永远不能以产生 copy-constructor 的方式实例化,正如 c++ 标准中的以下两个引用所示:

    [class.copy]

    2) 类 X 的 非模板 构造函数是 复制构造函数,如果它的第一个参数是 X&amp;const X&amp;、@ 类型987654326@ 或 const volatile X&amp; 或者没有其他参数,或者所有其他参数都有默认参数 (8.3.6)。

    ...

    6) 如果类X 的第一个参数是X 类型(可选的cv 限定)并且没有其他参数或者所有其他参数都具有默认参数,则类X 的构造函数声明是格式错误的. 永远不会实例化成员函数模板来生成这样的构造函数签名。

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

    [class.copy]

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


struct Obj {
  template<typename T>
  Obj (T const&) { }
  Obj (Obj&&) { }
};

...

Obj a;
Obj b (a);

考虑到前面提到的 c++ 标准中的引用,我们可以很容易地看到,Obj 的上述定义在语义上等同于下面的定义,因为我们显式声明的 move-constructor 将使我们的隐式声明复制构造函数= delete;

struct Obj {
  template<typename T>
  Obj (T const&) { }
  Obj (Obj const&) = delete;
  Obj (Obj&&) { }
};

根据重载解析的规则,删除的函数在试图找到最佳匹配时仍然参与,但如果他们赢得了最佳匹配的战斗,则程序是错误的。这正是 sn-p 中正在发生的事情。

Obj (Obj const&amp;) = deletetemplate&lt;typename T&gt; Obj (T const&amp;) 更合适,但由于无法调用复制构造函数,因此 sn-p 无法编译。

【讨论】:

  • +1 您的答案实际上是正确的(而我的(已删除)错误的)。我没有看到我引用的子句实际上与非引用限定的假定复制或移动构造函数有关。 /cc @juanchopanza
  • 提问者说他​​知道模板构造函数不是复制构造函数。编译失败的真正原因是模板构造函数和被删除的拷贝构造函数都参与了重载决议,被删除的拷贝构造函数被选中。
  • 模板可以以一种看起来像复制构造的方式构造对象(例如,想象一个涉及单个隐式转换的构造)。问题是有一个复制构造函数参与重载解析。
  • @neverhoodboy 您如何看待更新后的答案?
  • @FilipRoséen:我会说它既正确又具有信息性。感谢您的努力。
猜你喜欢
  • 1970-01-01
  • 2011-05-24
  • 1970-01-01
  • 2016-09-12
  • 1970-01-01
  • 2016-03-22
  • 1970-01-01
  • 2017-09-27
  • 2020-09-02
相关资源
最近更新 更多