为什么标准不将模板构造函数视为复制构造函数?
Why doesn't the standard consider a template constructor as a copy constructor?
这里是拷贝构造函数的定义,[class.copy.ctor/1]:
A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments ([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
。所以看起来我的模板构造函数是一个复制构造函数,至少它的行为像一个(它是在通常调用复制构造函数的上下文中调用的)。
为什么文中有"non-template"要求?
复制构造函数的形式为 X(X& ) 或 (X const&),如果您没有自己声明,编译器会为您提供。如果您使用模板 classes.
可能会出现非模板问题
假设有一个模板 class,它有一个模板复制构造函数。问题是,当您使用具有相同模板类型的此 class 的另一个实例实例化 class 时,您的模板复制构造函数将不会被调用。
问题不在于您的复制构造函数模板不匹配。问题是隐式复制构造函数不是函数模板,在重载解析方面,非模板优于模板特化。
来源:
让我们暂时搁置模板。如果 class 没有声明复制构造函数,则会生成一个隐式默认的复制构造函数。它可能被定义为已删除,但它仍然是默认值。
成员模板不是成员函数。成员仅在需要时从中实例化。
那么,编译器如何仅根据 class 定义就知道是否需要 T = Foo
的特化?它不能。但这正是它需要决定如何处理对隐式默认复制构造函数(和移动构造函数)的潜在需求的基础。那变得凌乱。
最简单的方法是排除模板。无论如何,我们总会有一些复制构造函数,它会默认做正确的事情TM,并且会受到重载决议的青睐,因为它不是从模板实例化的。
Why is the "non-template" requirement there in the text?
鉴于不同,复制构造函数可以是模板。在存在复制构造函数模板的情况下,非复制构造函数如何不歧义?考虑一下:
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
可以通过转换或普通构造来实现,但允许从非 [=13= 复制构造]对象将复制的概念更改为包括转换的复制。但这已经可以用现有方案实现(转换或非复制构造)。
In this example, here will be printed. So it seems that my template constructor is a copy constructor
您展示的示例未调用复制构造,而是普通的隐式构造。如果将构造函数模板更改为
template <typename T>
Foo(const T &) {
// ^^^^^
printf("here\n");
}
然后 Foo b = a;
导致调用编译器生成的复制构造函数。请注意,编译器生成的复制构造函数具有此签名:
Foo(const Foo&);
这需要在 Foo b = a;
中向 a
添加一个 const
限定符。您代码段中的原始构造函数模板 Foo(T&)
更匹配,因为没有添加 const
-qualifier。
这里是拷贝构造函数的定义,[class.copy.ctor/1]:
A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments ([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
。所以看起来我的模板构造函数是一个复制构造函数,至少它的行为像一个(它是在通常调用复制构造函数的上下文中调用的)。
为什么文中有"non-template"要求?
复制构造函数的形式为 X(X& ) 或 (X const&),如果您没有自己声明,编译器会为您提供。如果您使用模板 classes.
可能会出现非模板问题假设有一个模板 class,它有一个模板复制构造函数。问题是,当您使用具有相同模板类型的此 class 的另一个实例实例化 class 时,您的模板复制构造函数将不会被调用。
问题不在于您的复制构造函数模板不匹配。问题是隐式复制构造函数不是函数模板,在重载解析方面,非模板优于模板特化。
来源:
让我们暂时搁置模板。如果 class 没有声明复制构造函数,则会生成一个隐式默认的复制构造函数。它可能被定义为已删除,但它仍然是默认值。
成员模板不是成员函数。成员仅在需要时从中实例化。
那么,编译器如何仅根据 class 定义就知道是否需要 T = Foo
的特化?它不能。但这正是它需要决定如何处理对隐式默认复制构造函数(和移动构造函数)的潜在需求的基础。那变得凌乱。
最简单的方法是排除模板。无论如何,我们总会有一些复制构造函数,它会默认做正确的事情TM,并且会受到重载决议的青睐,因为它不是从模板实例化的。
Why is the "non-template" requirement there in the text?
鉴于不同,复制构造函数可以是模板。在存在复制构造函数模板的情况下,非复制构造函数如何不歧义?考虑一下:
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
可以通过转换或普通构造来实现,但允许从非 [=13= 复制构造]对象将复制的概念更改为包括转换的复制。但这已经可以用现有方案实现(转换或非复制构造)。
In this example, here will be printed. So it seems that my template constructor is a copy constructor
您展示的示例未调用复制构造,而是普通的隐式构造。如果将构造函数模板更改为
template <typename T>
Foo(const T &) {
// ^^^^^
printf("here\n");
}
然后 Foo b = a;
导致调用编译器生成的复制构造函数。请注意,编译器生成的复制构造函数具有此签名:
Foo(const Foo&);
这需要在 Foo b = a;
中向 a
添加一个 const
限定符。您代码段中的原始构造函数模板 Foo(T&)
更匹配,因为没有添加 const
-qualifier。