C++ 模板构造函数优先于普通复制和移动构造函数?
以下程序的输出C++ 模板构造函数优先于普通复制和移动构造函数?,c++,c++11,C++,C++11,以下程序的输出 #include <iostream> using namespace std; struct X { X(const X&) { cout << "copy" << endl; } X(X&&) { cout << "move" << endl; } template<class T> X(T
#include <iostream>
using namespace std;
struct X
{
X(const X&) { cout << "copy" << endl; }
X(X&&) { cout << "move" << endl; }
template<class T> X(T&&) { cout << "tmpl" << endl; }
};
int main()
{
X x1 = 42;
X x2(x1);
}
所需输出为:
tmpl
copy
为什么具体副本构造函数不优先于模板构造函数
有没有办法修复它,使复制和移动构造函数重载优先于模板构造函数?好吧,这是因为 在重载解析阶段,当函数模板实例化时,
T
被推断为X&
,因此T&&
(即X&&
)由于引用折叠而变为X&
,来自函数模板的实例化函数变得完全匹配,复制构造函数需要从X&
转换为const X&
(这就是为什么它没有被选择为次匹配)
但是,如果从复制构造函数中删除常量
,则首选复制构造函数。试试这个:
X(/*const*/ X&) { cout << "copy" << endl; }
也是预期的。在选择构造函数时,正常的重载解析规则仍然适用-并且采用非常量左值引用的构造函数(对于参数推导后的模板构造函数)比采用常量左值引用的构造函数更匹配 当然,您可以添加另一个重载,使用非常量左值引用,即
X(X&) { cout << "copy" << endl; }
如果不想添加另一个构造函数(如其他答案所建议的),可以使用SFINAE通过以下方式替换模板构造函数来约束调用:
template<class T
, typename std::enable_if<not std::is_same<X, typename std::decay<T>::type>::value, int>::type = 0
> X(T&&) { cout << "tmpl " << endl; }
template X(T&&){我是否还需要添加X(const X&&)
或者这是不可能的?在没有模板构造函数的情况下,是否存在移动或复制构造函数会匹配的其他情况?@andreTomazosfathomlingcorps:SFINAE可以帮助您,这样您就可以完整地保留两个函数签名(我认为这很重要)。例如,您可以在函数模板中使用std::enable_if
,仅启用所需的情况。是的,如果您碰巧有一个常量值,例如fromconst X f();
和X x3(f())
。然后,在这种情况下,初始值设定项是一个派生类,它也将使用模板构造函数。下面是与此问题相关的最后一个类:
X(X&) { cout << "copy" << endl; }
const X f()
{ return X(); }
struct Y : X
{ Y() { } };
int main()
{
X x3(f()); // const-qualified rvalue
Y y;
X x4(y); // derived class
}
template<class T
, typename std::enable_if<not std::is_same<X, typename std::decay<T>::type>::value, int>::type = 0
> X(T&&) { cout << "tmpl " << endl; }