简体   繁体   English

为什么标准不将模板构造函数视为复制构造函数?

[英]Why doesn't the standard consider a template constructor as a copy constructor?

Here's the definition of copy constructor, [class.copy.ctor/1] : 这是复制构造函数的定义, [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]). 如果X类的第一个参数是X&,const X&,volatile X&或const volatile X&,并且没有其他参数或者所有其他参数都有默认参数([dcl。],则X类的非模板构造函数是一个复制构造函数。 fct.default])。

Why does the standard exclude templates as copy constructors? 为什么标准将模板排除为复制构造函数?

In this simple example, both constructors are copy constructors: 在这个简单的例子中,两个构造函数都是复制构造函数:

struct Foo {
    Foo(const Foo &); // copy constructor
    Foo(Foo &);       // copy constructor
};

See this similar example: 看到这个类似的例子:

struct Foo {
     Foo() = default;

     template <typename T>
     Foo(T &) {
         printf("here\n");
     }
};

int main() {
    Foo a;
    Foo b = a;
}

In this example, here will be printed. 在此示例中,将打印here So it seems that my template constructor is a copy constructor, at least it behaves like one (it is called in a context where copy constructors are usually called). 所以我的模板构造函数似乎是一个复制构造函数,至少它表现得像一个(它在通常调用复制构造函数的上下文中调用)。

Why is the "non-template" requirement there in the text? 为什么文本中存在“非模板”要求?

Let's put templates aside for a second. 让模板放在一边一秒钟。 If a class doesn't declare a copy constructor, an implicitly defaulted one is generated. 如果类未声明复制构造函数,则会生成隐式默认值。 It may be defined as deleted, but it's defaulted nonetheless. 它可能被定义为已删除,但它仍然是默认的。

A member template is not a member function. 成员模板不是成员函数。 Members are instantiated from it only when needed. 成员仅在需要时才从中实例化。

So how can a compiler know from the class definition alone whether or not a specialization with T = Foo will ever be needed? 那么编译器如何才能从类定义中知道是否需要使用T = Foo It can't. 它不能。 But it's exactly that on which it needs to base a decision of how to handle a potential need for an implicitly defaulted copy constructor (AND move constructor). 但正是在这个问题上,它需要根据如何处理隐式默认复制构造函数(AND移动构造函数)的潜在需求做出决定。 That becomes messy. 那变得凌乱。

The easiest approach is to exclude templates. 最简单的方法是排除模板。 We'll always have some copy constructor anyway, it will do the correct thing TM by default, and will be favored by overload resolution because it's not instantiated from a template. 无论如何,我们总是会有一些复制构造函数,它默认会执行正确的TM ,并且会被重载解析所支持,因为它不是从模板中实例化的。

Why is the "non-template" requirement there in the text? 为什么文本中存在“非模板”要求?

Given it were different and copy constructors could be templates. 鉴于它是不同的,复制构造函数可以是模板。 How could a non-copy constructor not be ambiguous in the presence of a copy constructor template? 如果存在复制构造函数模板,非复制构造函数怎么可能不明确? Consider this: 考虑一下:

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 &) {}
};

Besides, constructing a Foo from an object that is not a Foo can be achieved by either conversion or ordinary construction, but allowing for copy-construction from a non- Foo object changes the notion of copying to copying including conversion . 此外,构造Foo从一个对象,该对象是不是一个Foo可以通过转化或普通的结构来实现的,但是允许从一个非复制结构Foo对象改变复制的概念来复制包括转换 But this can already be implemented with the existing scheme (conversion or non-copy construction). 但这已经可以用现有方案(转换或非复制构造)实现。

In this example, here will be printed. 在此示例中,将打印此处。 So it seems that my template constructor is a copy constructor 所以我的模板构造函数似乎是一个复制构造函数

The example that you show doesn't invoke copy construction, but an ordinary, implicit construction. 您显示的示例不会调用复制构造,而是调用普通的隐式构造。 If you change the constructor template to 如果您将构造函数模板更改为

template <typename T>
Foo(const T &) {
//  ^^^^^
    printf("here\n");
}

then Foo b = a; 那么Foo b = a; results in the compiler-generated copy constructor being called. 导致编译器生成的复制构造函数被调用。 Note that the copy ctor generated by the compiler has this signature: 请注意,编译器生成的copy ctor具有以下签名:

Foo(const Foo&);

This requires adding a const -qualifier to a in Foo b = a; 这需要增加一个const -qualifier到aFoo b = a; . The original constructor template Foo(T&) in your snippet is a better match, as no const -qualifier is added. 您的代码段中的原始构造函数模板Foo(T&)是更好的匹配,因为没有添加const -qualifier。

A copy constructor is of the form X(X& ) or (X const&), and it will be provided for you by the compiler if you didn't declare one yourself. 复制构造函数的形式为X(X&)或(X const&),如果您没有自己声明,它将由编译器为您提供。 Non-template comes here probably due to issues if you use template classes. 如果您使用模板类,非模板可能会因此而出现问题。

Let's say there is a template class that has a template copy constructor. 假设有一个模板类,它有一个模板复制构造函数。 The problem is that when you instantiate that class using another instance of this class with the same template type, your template copy constructor will not be called. 问题是,当您使用具有相同模板类型的此类的另一个实例来实例化该类时,将不会调用模板复制构造函数。

The issue isn't that your copy constructor template doesn't match. 问题不在于您的复制构造函数模板不匹配。 The issue is that the implicit copy constructor is not a function template, and non-templates are preferred to template specializations when it comes to overload resolution. 问题是隐式复制构造函数不是函数模板,并且在涉及重载解析时,非模板优先于模板特化。

Source: C++ template copy constructor on template class 来源: 模板类上的C ++模板复制构造函数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM