标准为何不将模板构造函数视为副本构造函数?

gez*_*eza 32 c++ templates constructor copy-constructor language-lawyer

这是复制构造函数[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
};
Run Code Online (Sandbox Code Playgroud)

参见以下类似示例:

struct Foo {
     Foo() = default;

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

int main() {
    Foo a;
    Foo b = a;
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,here将被打印。因此,似乎我的模板构造函数是一个复制构造函数,至少它的行为类似于一个(在通常调用复制构造函数的上下文中被调用)。

为什么文本中存在“非模板”要求?

Sto*_*ica 31

让我们将模板放置一秒钟。如果一个类未声明副本构造函数,则将生成一个隐式默认的副本构造函数。可以将其定义为已删除,但是仍然默认设置。

成员模板不是成员函数。仅在需要时才从中实例化成员。

那么,编译器如何仅从类定义中知道是否T = Foo将需要进行专业化?不行 但这正是需要决定如何处理隐式默认副本构造函数(AND move构造函数)的基础。变得混乱了。

最简单的方法是排除模板。无论如何,我们总会有一些拷贝构造函数,它在默认情况下会做正确的事情TM,并且由于不是从模板实例化的,所以它会受到重载解析的青睐。

  • @YSC:打印出来,因为传递的参数不是const,所以模板比隐式模板更好。但是(对我而言)不将模板专业化称为复制构造函数是令人困惑的。但是由于StoryTeller的解释,该标准会这样做。至少,这是一个明智的解释 (8认同)
  • 因此,基本上,您说这是因为以下规则:“如果类定义未显式声明一个副本构造函数,则将隐式声明一个非显式的构造函数”。而且,无论模板化构造函数如何,我们仍然希望定义通常的隐式副本构造函数。是的,这似乎是解释。 (5认同)
  • 您对Q所示程序中的g ++和clang ++打印“这里”有何看法? (3认同)
  • @ YSC-也许...默认值具有const限定参数,而模板则没有。所以这是一个更好的搭配。T const&`仍然会发生吗? (3认同)
  • @YSC-老实说?对我来说感觉像个虫子。目前,我无法进行更多评论。这是我的电话 (2认同)
  • @StoryTeller好抓住,不,它不是:http://coliru.stacked-crooked.com/a/1de13995fde629be (2认同)

lub*_*bgr 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 &) {}
};
Run Code Online (Sandbox Code Playgroud)

此外,构造Foo从一个对象,它是一个不Foo可通过转化或普通的结构来实现的,但是允许复制结构从非Foo对象改变的概念复制复制包括转化。但这可以通过现有方案(转换或非复制构造)实现。

在此示例中,将在此处打印。所以看来我的模板构造函数是一个复制构造函数

您显示的示例不会调用副本构造,而是一个普通的隐式构造。如果将构造函数模板更改为

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

然后Foo b = a;导致编译器生成的副本构造函数被调用。请注意,由编译器生成的副本ctor具有以下签名:

Foo(const Foo&);
Run Code Online (Sandbox Code Playgroud)

这需要增加一个const-qualifier到aFoo b = a;Foo(T&)代码段中的原始构造函数模板是更好的匹配,因为未const添加-qualifier。

  • 是的!确实,整个const与非const的事情。+1 (4认同)