#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?
}构造函数的模板重载适用于两个声明(u2和u3)。但是,当int传递给构造函数时,将选择非模板重载。当调用复制构造函数时,将选择模板重载。据我所知,在过载解析期间,非模板函数总是比模板函数更好。为什么复制构造函数的处理方式不同?
发布于 2019-09-12 15:28:03
据我所知,在过载解析过程中,非模板函数总是优先于模板函数。
只有当专门化和非模板完全相同时,这才是正确的。不过,这里的情况并非如此。调用uct u3(u1)时,重载集将获得
uct(const uct &)
uct(uct &) // from the template现在,由于u1不是const,所以必须应用const转换来调用复制构造函数。要调用模板专门化,它不需要做任何操作,因为它是完全匹配的。这意味着模板获胜,因为它是更好的匹配。
要停止这种情况,您可以做的一件事是使用SFINAE将模板函数限制为仅在T不是uct时才调用。看起来就像
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; }发布于 2019-09-12 15:59:17
当尝试调用复制构造函数时,将选择模板重载。据我所知,在过载解析过程中,非模板函数总是优先于模板函数。为什么复制构造函数的处理方式不同?
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在T与uct相同的情况下禁用重载。
template <typename T, std::enable_if_t<!std::is_same_v<std::decay_t<T>, uct>>>
uct(T&&)
{
std::cerr << "template" << std::endl;
}发布于 2019-09-12 15:30:52
问题是模板构造函数没有限定const,而非模板复制构造函数的参数中有限定符const。如果要将对象u1声明为const对象,则将调用非模板复制构造函数。
来自C++ STandard (7标准转换)
1标准转换是内建意义的隐式转换。条例草案第7条列举这类转换的全部内容。标准转换序列是按以下顺序进行的标准转换序列: (1.4) -零或一次资格转换
因此,复制构造函数需要一个标准转换,而模板构造函数不需要这样的转换。
https://stackoverflow.com/questions/57909923
复制相似问题