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