C++中为何模板构造函数优先级高于拷贝/移动构造函数?
问题:为何模板通用构造函数被选中而非拷贝(或移动)构造函数?
请看以下程序:
#include <variant> struct A{ A() {} ~A() {} A(const A&) {} A& operator = (const A&) { return *this;} A(A&&) {} A& operator = (A&& ) { return *this; } using var = std::variant<int, float>; var v; template<typename T> A(T&& t): v(std::forward<T>(t)) {} }; struct B { A m_a; B(A a) : m_a(a) //calls template constructor instead of copy! {} };
核心原因
模板构造函数的推导结果比拷贝构造函数的匹配度更高,具体分析如下:
- 在
B的构造函数中,m_a(a)里的a是非const的左值(B(A a)的参数a是传值进来的左值)。 - 拷贝构造函数
A(const A&)接受的是const A的引用,匹配时需要给a添加const限定,属于低一级的匹配。 - 模板构造函数
template<typename T> A(T&& t)会通过引用折叠规则推导为T=A&,实例化出A(A& t),它直接接受非const左值a,无需任何限定转换,匹配度完全贴合。
根据C++重载决议规则:可行重载中匹配度最高的函数会被选中,因此模板构造函数优先被调用。
解决办法
若要让拷贝构造函数优先生效,可采用以下两种方式:
- 添加非const版本的拷贝构造函数:
A(A&) {} // 非模板函数优先级高于模板实例化函数
- 给模板构造函数添加SFINAE约束,排除
T为A相关类型的情况:
template<typename T, std::enable_if_t<!std::is_same_v<std::decay_t<T>, A>, int> = 0> A(T&& t): v(std::forward<T>(t)) {}
补充说明:我认为这并非《为何未调用此模板移动构造函数?》的重复问题,因为该问题询问的是为何模板构造函数未被调用?,而我询问的是为何模板构造函数被调用?,二者问题恰好相反。:)
内容的提问来源于stack exchange,提问作者Khurshid Normuradov
相关产品推荐
相关产品推荐

