【问题标题】:C++ template copy constructor on template class模板类上的 C++ 模板复制构造函数
【发布时间】:2015-12-08 20:56:17
【问题描述】:

我有一个模板类,它有一个模板复制构造函数。问题是当我使用具有相同模板类型的此类的另一个实例来实例化此类时,不会调用我的模板复制构造函数。为什么不匹配?

这里是sn-p的代码:

#include <iostream>

template <typename T>
class MyTemplateClass
{
    public:
        MyTemplateClass()
        {
            std::cout << "default constructor" << std::endl;
        }

        /*
        MyTemplateClass(const MyTemplateClass<T>& other)
        {
            std::cout << "copy constructor" << std::endl;
        }
        */

        template <typename U>
        MyTemplateClass(const MyTemplateClass<U>& other)
        {
            std::cout << "template copy constructor" << std::endl;
        }
};

int main()
{
    MyTemplateClass<int> instance;
    MyTemplateClass<int> instance2(instance);
    return EXIT_SUCCESS;
}

输出是

default constructor

但是如果我显式编写默认的复制构造函数(通过取消注释),那么输出变为

default constructor
copy constructor

我真的不明白。我使用本地编译器 (Clang 500.2.79) 和 this one (GCC 4.9.2) 对其进行了测试,得到了相同的结果。

【问题讨论】:

  • 模板永远不是(!)复制构造函数!
  • 复制构造函数永远不是模板。
  • 有一个隐式声明的复制构造函数,它是重载决议的首选。

标签: c++ templates copy-constructor


【解决方案1】:

当您的代码中没有复制构造函数时,编译器将隐式生成它。因此当这一行被执行时:

MyTemplateClass<int> instance2(instance);

复制构造函数 is 正在执行,但显然不是你的。我认为模板与它无关。

在此处了解更多信息:Implicitly-defined copy constructor

【讨论】:

    【解决方案2】:

    我认为 REACHUS 是对的。编译器正在生成一个默认的复制构造函数(就像使用非模板类一样)并且更喜欢它而不是模板,因为它更专业。

    您应该将“普通”复制构造函数设为私有,或者更好的是,使用 C++11 的“已删除”关键字将该函数标记为不可用。

    但是,这不会编译。抱歉,我当时无法对其进行测试。

    【讨论】:

    • 这两个建议都会使代码无法编译 - 不喜欢调用构造函数模板。
    • @Barry 为什么你认为在这种情况下声明一个已删除的复制构造函数不是一个好主意?
    • @REACHUS 这将使类不可复制。我不认为这是 OP 的目标。
    • 你是对的,它不会为我编译,但是为什么编译器会尝试使用删除的函数来代替模板?
    • 谁是“REACHUS”? (用户可能更改了屏幕名称。)
    【解决方案3】:

    复制构造函数的形式为X(X&amp; )(X const&amp;),如果您没有自己声明(或其他一些与此处无关的条件),编译器将为您提供。你没有,所以隐含地我们有以下一组候选人:

    MyTemplateClass(const MyTemplateClass&);
    template <typename U> MyTemplateClass(const MyTemplateClass<U>&);
    

    两者都适用

    MyTemplateClass<int> instance2(instance);
    

    两者都采用相同的确切参数。问题不在于您的复制构造函数模板不匹配。问题是隐式复制构造函数不是函数模板,在重载决议方面,非模板优先于模板特化。从 [over.match.best] 中,省略不相关的要点:

    鉴于这些定义,一个可行函数 F1 被定义为比另一个可行函数更好的函数 F2 如果对于所有参数 i,ICSi(F1) 不是比 ICSi(F2) 更差的转换序列,然后
    — [...]
    — F1 不是函数模板特化,F2 是函数模板特化,或者,如果不是,
    — [...]

    这就是为什么它在你的构造函数模板上调用你的隐式(然后是你的显式)复制构造函数。

    【讨论】:

    • 在重载解析方面,为什么非模板优先于模板特化?是因为在大多数情况下这是最好的选择吗?
    • @REACHUS 直接的答案是因为这是规则(添加了标准报价)。一般规则是 - 尽可能选择最具体的功能。非模板比模板更具体。
    • 好吧坦克,我的错误是认为不会生成复制构造函数。
    猜你喜欢
    • 1970-01-01
    • 2016-03-22
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多