在轉發參考上過載
提供轉發引用過載時必須非常小心,因為它可能匹配得太好了:
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
或類,這將使得該建構函式在前面描述的示例中形成錯誤(並因此從過載集中移除)。結果,呼叫了複製建構函式 - 這就是我們想要的。