C++ 转发参考上的重载

示例

提供转发参考过载时,您必须非常小心,因为它可能匹配得很好:

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,这会使该构造函数在前面描述的示例中格式不正确(因此从重载集中删除)。结果,调用了复制构造函数-这就是我们想要的。