2017-09-18 84 views
7
template<class _Other1, 
    class _Other2, 
    class = enable_if_t<is_constructible<_Ty1, _Other1>::value 
        && is_constructible<_Ty2, _Other2>::value>, 
    enable_if_t<is_convertible<_Other1, _Ty1>::value 
      && is_convertible<_Other2, _Ty2>::value, int> = 0> 
    constexpr pair(pair<_Other1, _Other2>&& _Right) 
     _NOEXCEPT_OP((is_nothrow_constructible<_Ty1, _Other1>::value 
      && is_nothrow_constructible<_Ty2, _Other2>::value)) 
    : first(_STD forward<_Other1>(_Right.first)), 
     second(_STD forward<_Other2>(_Right.second)) 
    { // construct from moved compatible pair 
    } 

template<class _Other1, 
    class _Other2, 
    class = enable_if_t<is_constructible<_Ty1, _Other1>::value 
        && is_constructible<_Ty2, _Other2>::value>, 
    enable_if_t<!is_convertible<_Other1, _Ty1>::value 
      || !is_convertible<_Other2, _Ty2>::value, int> = 0> 
    constexpr explicit pair(pair<_Other1, _Other2>&& _Right) 
     _NOEXCEPT_OP((is_nothrow_constructible<_Ty1, _Other1>::value 
      && is_nothrow_constructible<_Ty2, _Other2>::value)) 
    : first(_STD forward<_Other1>(_Right.first)), 
     second(_STD forward<_Other2>(_Right.second)) 
    { // construct from moved compatible pair 
    } 

實用文件VS 2017年線206, _Other1和_Other2是參數,這是的std ::對的建設FUNC, 和我們使用其他1和其它2至初始化 「第一」和「秒」,

我覺得is_constructible就夠了,爲什麼我們在這裏用is_convertible
順便說一句,class = enable_if_t< ... ::value>enable_if_t< ... ::value,int> = 0之間有什麼區別?爲何'is_convertible'在<utility> std :: pair(STL)?

+0

這是爲了實現[\ [pairs.pair \]/12](http://eel.is/c++draft/pairs.pair#12.sentence-2)。 – cpplearner

回答

9

我覺得is_constructible是不夠的,我們爲什麼使用is_convertible這裏?

這裏的目標是妥善處理explicit的構造。考慮只是做前者,而試圖寫一個包裝(使用REQUIRES這裏隱藏任何你想要的方式來SFINAE):

template <class T> 
class wrapper { 
public: 
    template <class U, REQUIRES(std::is_constructible<T, U&&>::value)> 
    wrapper(U&& u) : val(std::forward<U>(u)) { } 
private: 
    T val; 
}; 

如果這一切我們有,則:

struct Imp { Imp(int); }; 
struct Exp { explicit Exp(int); }; 

Imp i = 0; // ok 
Exp e = 0; // error 
wrapper<Imp> wi = 0; // ok 
wrapper<Exp> we = 0; // ok?!? 

我們一定不要不想讓最後一個人沒事 - 這打破了對Exp的期待!

現在,s_constructible<T, U&&>如果可以從U&&直接初始化T - 如果T(std::declval<U&&>())是有效的表達式,則爲真。

is_convertible<U&&, T>,在另一方面,檢查是否有可能複製 -initialize一個TU&&。也就是說,如果T copy() { return std::declval<U&&>(); }有效。

不同的是,如果轉換爲explicit後者不起作用:

+-----+--------------------------+------------------------+ 
|  | is_constructible<T, int> | is_convertible<int, T> | 
+-----+--------------------------+------------------------+ 
| Imp |  true_type   |  true_type  | 
| Exp |  true_type   |  false_type  | 
+-----+--------------------------+------------------------+ 

爲了正確地傳播明確性,我們需要使用兩個性狀在一起 - 我們可以創建元性狀出來的其中:

template <class T, class From> 
using is_explicitly_constructible = std::integral_constant<bool, 
    std::is_constructible<T, From>::value && 
    !std::is_convertible<From, T>::value>; 

template <class T, class From> 
using is_implicitly_constructible = std::integral_constant<bool, 
    std::is_constructible<T, From>::value && 
    std::is_convertible<From, T>::value>; 

這兩個特點是不相交的,所以我們可以編寫絕對不是都可行的兩個構造模板,其中一個構造函數是明確的,另一種是不:

template <class T> 
class wrapper { 
public: 
    template <class U, REQUIRES(is_explicitly_constructible<T, U&&>::value)> 
    explicit wrapper(U&& u) : val(std::forward<U>(u)) { } 

    template <class U, REQUIRES(is_implicitly_constructible<T, U&&>::value)> 
    wrapper(U&& u) : val(std::forward<U>(u)) { } 
private: 
    T val; 
}; 

這給了我們所期望的行爲:

wrapper<Imp> wi = 0; // okay, calls non-explicit ctor 
wrapper<Exp> we = 0; // error 
wrapper<Exp> we2(0); // ok 

這就是實現在這裏做什麼 - 除了代替他們都寫了explicit LY條件兩元的特徵。

8

爲了實現[pairs.pair]/12

此構造不得參與重載解析,除非is_­constructible_­v<first_­type, U1&&>是真實的, is_­constructible_­v<second_­type, U2&&>是真實的。 構造函數是明確的當且僅當is_­convertible_­v<U1&&, first_­type>爲假或 is_­convertible_­v<U2&&, second_­type>爲假。

+0

但是*如果其中一種或兩種類型都不可轉換,爲什麼*應該是「顯式」? –

+3

@ArneVogel如果不是'std :: is_convertible_v'檢查,則允許將類型隱式轉換爲顯式轉換的類型。 – Rakete1111

相關問題