这是复制构造函数[class.copy.ctor/1]的定义:
如果类X的第一个参数的类型为X&,const X&,volatile X&或const volatile X&类型,并且没有其他参数,或者所有其他参数都具有默认参数( [dcl.fct.default])。
为什么标准不将模板作为复制构造函数?
在这个简单的示例中,两个构造函数都是副本构造函数:
struct Foo {
Foo(const Foo &); // copy constructor
Foo(Foo &); // copy constructor
};
请参阅以下类似示例:
struct Foo {
Foo() = default;
template <typename T>
Foo(T &) {
printf("here\n");
}
};
int main() {
Foo a;
Foo b = a;
}
在此示例中,将打印here
。因此,看来我的模板构造函数是一个复制构造函数,至少它的行为类似于一个(在通常调用复制构造函数的上下文中被调用)。
为什么文本中存在“非模板”要求?
答案 0 :(得分:31)
让我们将模板放置一秒钟。如果一个类未声明副本构造函数,则将生成一个隐式默认的副本构造函数。可以将其定义为已删除,但仍默认为默认值。
成员模板不是成员函数。仅在需要时才从中实例化成员。
那么,编译器如何仅从类定义中知道是否需要使用T = Foo
进行专门化?不可以但这正是需要决定如何处理对隐式默认副本构造函数(AND移动构造函数)的潜在需求的基础。变得混乱了。
最简单的方法是排除模板。无论如何,我们总会有一些拷贝构造函数,它默认会做正确的事情 TM ,并且由于它不是从模板中实例化的,因此将受到重载解析的青睐。
答案 1 :(得分:10)
为什么文本中存在“非模板”要求?
鉴于情况有所不同,复制构造函数可以是模板。在存在复制构造函数模板的情况下,非复制构造函数如何不歧义?考虑一下:
struct Foo {
// ctor template: clearly useful and necessary
template <typename T>
Foo(const T&) {}
// copy ctor: same signature! can't work
template <typename T>
Foo(const T &) {}
};
此外,可以通过转换或普通构造来从非Foo
的对象构造Foo
,但可以从非Foo
的对象进行拷贝构造将复制的概念更改为包括转换的复制。但这可以通过现有方案(转换或非复制构造)来实现。
在此示例中,将在此处打印。所以看来我的模板构造函数是复制构造函数
您显示的示例不会调用副本构造,而是一个普通的隐式构造。如果您将构造函数模板更改为
template <typename T>
Foo(const T &) {
// ^^^^^
printf("here\n");
}
然后Foo b = a;
导致编译器生成的副本构造函数被调用。请注意,由编译器生成的副本ctor具有以下签名:
Foo(const Foo&);
这需要向const
中的a
添加一个Foo b = a;
限定词。您的代码段中的原始构造函数模板Foo(T&)
是更好的匹配,因为未添加const
限定符。
答案 2 :(得分:0)
复制构造函数的格式为X(X&)或(X const&),如果您自己没有声明,则编译器将为您提供该副本构造函数。如果使用模板类,则可能由于问题而出现非模板。
比方说,有一个模板类具有模板副本构造函数。问题在于,当您使用具有相同模板类型的该类的另一个实例实例化该类时,将不会调用您的模板副本构造函数。
问题不是您的副本构造器模板不匹配。问题在于隐式副本构造函数不是函数模板,而在涉及重载解析时,非模板优先于模板专业化。