首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么模板构造函数优先于复制构造函数?

为什么模板构造函数优先于复制构造函数?
EN

Stack Overflow用户
提问于 2019-09-12 15:23:18
回答 3查看 2.2K关注 0票数 40
代码语言:javascript
复制
#include <iostream>

struct uct
{
    uct() { std::cerr << "default" << std::endl; }

    uct(const uct &) { std::cerr << "copy" << std::endl; }
    uct(      uct&&) { std::cerr << "move" << std::endl; }

    uct(const int  &) { std::cerr << "int" << std::endl; }
    uct(      int &&) { std::cerr << "int" << std::endl; }

    template <typename T>
    uct(T &&) { std::cerr << "template" << std::endl; }
};

int main()
{
    uct u1    ; // default
    uct u2( 5); // int
    uct u3(u1); // template, why?
}

柯尔鲁

构造函数的模板重载适用于两个声明(u2u3)。但是,当int传递给构造函数时,将选择非模板重载。当调用复制构造函数时,将选择模板重载。据我所知,在过载解析期间,非模板函数总是比模板函数更好。为什么复制构造函数的处理方式不同?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-09-12 15:28:03

据我所知,在过载解析过程中,非模板函数总是优先于模板函数。

只有当专门化和非模板完全相同时,这才是正确的。不过,这里的情况并非如此。调用uct u3(u1)时,重载集将获得

代码语言:javascript
复制
uct(const uct &)
uct(uct &) // from the template

现在,由于u1不是const,所以必须应用const转换来调用复制构造函数。要调用模板专门化,它不需要做任何操作,因为它是完全匹配的。这意味着模板获胜,因为它是更好的匹配。

要停止这种情况,您可以做的一件事是使用SFINAE将模板函数限制为仅在T不是uct时才调用。看起来就像

代码语言:javascript
复制
template <typename T, std::enable_if_t<!std::is_same_v<uct, std::decay_t<T>>, bool> = true>
uct(T &&) { std::cerr << "template" << std::endl; }
票数 40
EN

Stack Overflow用户

发布于 2019-09-12 15:59:17

当尝试调用复制构造函数时,将选择模板重载。据我所知,在过载解析过程中,非模板函数总是优先于模板函数。为什么复制构造函数的处理方式不同?

代码语言:javascript
复制
template <typename T>
uct(T &&) { std::cerr << "template" << std::endl; }
//    ^^

模板版本被选中的原因是编译器能够

生成一个具有签名(T &)的构造函数,该构造函数更适合并因此被选中。

  • 如果您将签名从uct u1更改为const uct u1,那么它将适合复制构造函数(因为u1最初不是const )。
  • 如果您将签名从uct(const uct &)更改为uct(uct&),这将是一个更合适的选择,它将选择这个版本而不是模板版本。
  • 此外,如果您使用了uct(uct&&),则将选择uct u3(std::move(u1));

要解决这个问题,可以使用SFINAE在Tuct相同的情况下禁用重载。

代码语言:javascript
复制
template <typename T, std::enable_if_t<!std::is_same_v<std::decay_t<T>, uct>>>
uct(T&&)
{
  std::cerr << "template" << std::endl;
}
票数 5
EN

Stack Overflow用户

发布于 2019-09-12 15:30:52

问题是模板构造函数没有限定const,而非模板复制构造函数的参数中有限定符const。如果要将对象u1声明为const对象,则将调用非模板复制构造函数。

来自C++ STandard (7标准转换)

1标准转换是内建意义的隐式转换。条例草案第7条列举这类转换的全部内容。标准转换序列是按以下顺序进行的标准转换序列: (1.4) -零或一次资格转换

因此,复制构造函数需要一个标准转换,而模板构造函数不需要这样的转换。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57909923

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档