简体   繁体   English

为什么模板构造函数首选复制构造函数?

[英]Why is template constructor preferred to copy constructor?

#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?
}

coliru coliru

Template overload of constructor fits to both declarations ( u2 and u3 ). 构造函数的模板重载适用于两个声明( u2u3 )。 But when int is passed to constructor, non-template overload is chosen. 但是当int传递给构造函数时,会选择非模板重载。 When copy constructor is tried to be called, template overload is chosen. 尝试调用复制构造函数时,会选择模板重载。 As far as I know non-template function is always preferred to template function during overload resolution. 据我所知,在重载解析期间,非模板函数总是优先于模板函数。 Why is copy constructor handled differently? 为什么复制构造函数处理方式不同?

As far as I know non-template function is always preferred to template function during overload resolution. 据我所知,在重载解析期间,非模板函数总是优先于模板函数。

This is true, only when the specialization and the non template are exactly the same. 这是真的,只有当专业化和非模板完全相同时。 This is not the case here though. 但事实并非如此。 When you call uct u3(u1) The overload sets gets 当你调用uct u3(u1) ,重载集得到了

uct(const uct &)
uct(uct &) // from the template

Now, since u1 is not const it would have to apply a const transformation to call the copy constructor. 现在,因为u1不是const,所以必须应用const转换来调用复制构造函数。 To call the template specialization is needs to do nothing since it is an exact match. 要调用模板特化是需要什么都不做,因为它是完全匹配。 That means the template wins as it is the better match. 这意味着模板赢了,因为它是更好的匹配。

To stop this one thing you can do is use SFINAE to limit the template function to only be called when T is not a uct . 要停止这一点,您可以使用SFINAE来限制模板功能,只有在T不是uct时才能调用。 That would look like 那看起来像

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; }

The problem is that the template constructor has no the qualification const while the non-template copy constructor has the qualifier const in its parameter. 问题是模板构造函数没有限定const ,而非模板复制构造函数在其参数中有限定符const。 If you will declare the object u1 as a const object then the non-template copy constructor will be called. 如果要将对象u1声明为const对象,则将调用非模板复制构造函数。

From the C++ STandard (7 Standard conversions) 来自C ++标准(7个标准转换)

1 Standard conversions are implicit conversions with built-in meaning. 1标准转化是具有内置含义的隐式转化。 Clause 7 enumerates the full set of such conversions. 第7条列举了全套此类转换。 A standard conversion sequence is a sequence of standard conversions in the following order: 标准转换序列是一系列标准转换,顺序如下:

(1.4) — Zero or one qualification conversion (1.4) - 零或一个资格转换

So the copy constructor needs one standard conversion while the template constructor sies not require such a conversion. 因此,复制构造函数需要一个标准转换,而模板构造函数不需要这样的转换。

When copy constructor is tried to be called, template overload is chosen. 尝试调用复制构造函数时,会选择模板重载。 As far as I know non-template function is always preferred to template function during overload resolution. 据我所知,在重载解析期间,非模板函数总是优先于模板函数。 Why is copy constructor handled differently? 为什么复制构造函数处理方式不同?

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

The reason the templated version gets picked is because the compiler is able 选择模板化版本的原因是因为编译器能够
to generate a constructor with signature (T &) which fits better and is chosen. 生成一个带有签名(T &)的构造函数,它更适合并被选中。

If you changed uct u1 to const uct u1 it would fit the copy constructor. 如果你将uct u1更改为const uct u1 ,它将适合复制构造函数。
If you changed the signature to uct(uct&) it would be a better fit and it would choose that over the templated version. 如果您将签名更改为uct(uct&)那么它会更合适,并且会在模板化版本上选择。
Also, the uct(uct&&) would be chosen if you had used uct u3(std::move(u1)); 此外,如果您使用了uct u3(std::move(u1));则会选择uct(uct&&) uct u3(std::move(u1));

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

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