在转发参考上重载
提供转发引用过载时必须非常小心,因为它可能匹配得太好了:
struct A {
A() = default; // #1
A(A const& ) = default; // #2
template <class T>
A(T&& ); // #3
};
这里的意图是 A
是可复制的,并且我们有另一个可能初始化其他成员的构造函数。然而:
A a; // calls #1
A b(a); // calls #3!
建筑呼叫有两个可行的匹配:
A(A const& ); // #2
A(A& ); // #3, with T = A&
两者都是精确匹配,但是 #3
引用了比 #2
更少的 cv 资格对象,因此它具有更好的标准转换序列并且是最好的可行功能。
这里的解决方案是始终约束这些构造函数(例如使用 SFINAE):
template <class T,
class = std::enable_if_t<!std::is_convertible<std::decay_t<T>*, A*>::value>
>
A(T&& );
这里的类型特征是从考虑中公开且明确地从 A
中排除任何 A
或类,这将使得该构造函数在前面描述的示例中形成错误(并因此从重载集中移除)。结果,调用了复制构造函数 - 这就是我们想要的。