【问题标题】:Why is a templatized copy constructor not called? [duplicate]为什么不调用模板化的复制构造函数? [复制]
【发布时间】:2021-01-01 01:22:50
【问题描述】:

为什么下面的代码编译失败(抱怨删除了拷贝构造函数):

struct C {
    int i;
    
    C(const C&) = delete;
    C(int i) : i(i) {}
    
    template <typename T>
    C(const T& value) {
      cout << "in templatized constructor!\n";
      this->i = value.i * 2;
    }

};

int main()
{
   C s1{4};
   C s2{s1};

   cout << s2.i;
}

但是当我从模板化复制构造函数中删除 const 时,一切正常:

    template <typename T>
    C(T& value) {
      cout << "in templatized constructor!\n";
      this->i = value.i * 2;
    }

两个问题:

(1) 生成的复制构造函数被删除时,为什么不使用模板构造函数作为后备?

(2) 即使“模板不能是复制构造函数” - C(T&); 如何/为什么构造函数被用作复制构造函数(在第二个示例中)?这肯定与模板不能是复制构造函数的想法相矛盾吗?

【问题讨论】:

  • 线索:尝试声明const C s1{4};,看看是否“一切正常”。剧透:它没有。
  • 模板永远不是复制构造函数。
  • 没有模板化复制构造函数之类的东西。复制构造函数永远不是模板。模板永远不是复制构造函数。
  • 顺便说一句,这究竟是为什么?在第一种情况下,最佳匹配是删除的函数。在第二种情况下,最佳匹配是模板。
  • "隐式生成的复制构造函数已被删除,为什么不回退" 因为= delete 并不意味着“假装我不在这里”。它的意思是“我在这里,但不要试图给我打电话”。

标签: c++ templates


【解决方案1】:

这只是重载决议。在C s2{s1}; 中,您正在寻找可以采用(非constC 左值参数的C 的构造函数。对于template&lt;typename T&gt; C(T const&amp;),这个构造函数可以匹配参数列表的“最接近”设置T = C,所以你得到C(C const&amp;)(这个T的解决方案是通过模板参数推导找到的,我们不需要进入)。复制构造函数C(C const&amp;) = delete; 也可以使用此参数列表调用。所涉及的两个隐式转换序列(C lvalue 经历身份转换以绑定到C const&amp;)也完全相同,因此没有一个重载立即比另一个“更好”。但是,deleted 不是模板,因此无论如何它被认为更好。选择了deleted 重载,导致错误。如果你有template&lt;typename T&gt; C(T&amp;),那么它可以更接近给定的参数列表,通过设置T = C 来获得C(C&amp;)。现在,C 左值绑定到C&amp;(模板的情况)的隐式转换序列比C 左值绑定到C const&amp;(复制构造函数)的隐式转换序列更好,由于要添加的限定符较少,所以现在模板获胜并且代码编译。

针对 cme​​ts,您的模板化构造函数确实不是复制构造函数。 According to cppreference,

T 类的复制构造函数是非模板构造函数...

另外,您可能误解了= delete; 的含义。 C(C const&amp;) = delete; not 的意思是“not 这个签名没有重载”,它的意思是“这个签名有一个重载,并且试图调用它是一个错误”。您不能没有复制构造函数作为类构造函数的重载之一。 deleteing 它只会使使用该重载成为错误,但不会阻止重载解决方案选择另一个重载。

【讨论】:

  • 谢谢。如果复制构造函数没有生成而不是显式删除怎么办?即通过复制赋值运算符的定义。还是等同于 = delete?
  • @horseyguy 复制构造函数总是被声明并且总是参与重载决议。您的示例是隐式的 deleted 构造函数。
  • 谢谢。最后一个问题......在什么意义上不是模板化的非 const 构造函数不是复制构造函数?我知道标准说它必须是非模板,但编译器仍在调用它来制作非 const 实例的副本,所以即使它是模板,它是否在所有方面都充当复制构造函数?
  • 如果你例如没有声明复制构造函数,那么编译器不会将您的模板识别为复制构造函数并自己声明一个。复制构造函数的形式还控制它(以及它的类)是否被认为是微不足道的,等等。
  • 感谢@HTNW - 我相信您的许多答案都不是微不足道的(例如已删除的构造函数仍参与重载决议并阻止模板化后备)以及您对复制构造函数的清晰描述- 即使非常量模板构造函数似乎是一个。我不知道为什么当链接的问题都没有涉及这些主题也没有如此明确的答案时,这个问题被标记为重复。我认为许多其他 C++ 菜鸟也会觉得这很重要/很有趣。谢谢!
猜你喜欢
  • 2022-01-27
  • 2011-05-24
  • 2020-01-14
  • 2021-02-18
  • 2014-01-14
  • 1970-01-01
  • 2021-05-14
  • 2012-02-28
相关资源
最近更新 更多