2015-09-25 113 views
2

這就是我想要的,一個「開關」型特徵,它返回具有滿足的條件==第一種類型:實現開關型特徵(與標準:: conditional_t鏈話費)

ext::select_t<condition1 == true, Type1, 
       condition2 == true, type2, 
       condition3 == true, type3> 

等,並且能夠根據需要添加儘可能多的條件/類型對。

我可以用的std ::條件本身(隨便舉個例子)做到這一點:

template<typename Number, 
     typename Distribution = std::conditional_t< 
       // IF 
       std::is_integral<Number>::value, 
       // RETURN INT 
       std::uniform_int_distribution<Number>, 
       // ELSE 
       std::conditional_t<std::is_floating_point<Number>::value, 
            // RETURN REAL 
            std::uniform_real_distribution<Number>, void>>> 

Number random(Number min, Number max) 
{ 
    static std::random_device rd; 
    static std::mt19937 mt(rd()); 

    Distribution dist(min, max); 

    return dist(mt); 
} 

,你可以看到它決定在我想根據傳遞的條件/類型是什麼樣的分佈編譯時間。

顯然,如果我嘗試添加更多的條件,這可以得到真正的醜陋真實的快速,想象我想要其中的10個。

,所以我試圖建立一個,但悲慘地失敗了:

template<bool B, typename T> 
struct cond 
{ 
    static constexpr bool value = B; 
    using type = T; 
}; 

template<typename Head, typename... Tail> 
struct select 
{ 
    using type = std::conditional_t<Head::value, typename Head::type, select<Tail...>>; 
}; 

template<typename Head> 
struct select<Head> 
{ 
    using type = std::conditional_t<Head::value, typename Head::type, void>; 
}; 

template<typename Head, typename... Tail> 
using select_t = typename select<Head, Tail...>::type; 

我試圖使該鏈表的結構是這樣我就可以得到條件/類型「對」的原因,所以我可以得到任何數那些使用可變參數模板,但是這使得它更醜陋的(和不工作):

using Type = std::select_t<cond<false, void>, 
          cond<false, int>, 
          cond<true, std::string>>; 

不僅看起來不那麼好,因爲我想最後的版本是,但它甚至不工作!它只在第一個條件爲真時才起作用。

有什麼可以遺漏嗎?我怎麼能以更乾淨的方式實現這一目標(至少對最終用戶而言)。

在此先感謝。

+0

如果沒有一個條件是真的會怎樣? – jrok

+0

如果沒有,它只是返回void。顯然,如果沒有真正的條件,最好的解決方案就是編譯失敗。取決於最終用戶的做法,void將(幾乎)總是使編譯失敗,但它可以以某種方式編譯正確並在代碼中產生錯誤,不知道如何解決這個問題。 – sap

回答

4

的問題是在你的基本情況:

using type = std::conditional_t<Head::value, typename Head::type, select<Tail...>>; 

你想成功(Head::value)使用的頭型(Head::type),但沒有使用尾部類型。但select<Tail...>不是尾巴類型。這是一個元函數。要真正地評價它:

using type = std::conditional_t< 
       Head::value, 
       typename Head::type, 
       typename select<Tail...>::type>; 

現在,這是有點低效率的,因爲你必須處理條件往上頂的整體。爲此,您可以編寫一個單獨的元函數,Boost.MPL稱爲eval_if。而不是採取一個布爾和兩種類型的,它需要一個布爾兩元函數:

template <bool B, typename TrueF, typename FalseF> 
struct eval_if { 
    using type = typename TrueF::type; 
}; 

template <typename TrueF, typename FalseF> 
struct eval_if<false, TrueF, FalseF> { 
    using type = typename FalseF::type; 
};  

template <bool B, typename T, typename F> 
using eval_if_t = typename eval_if<B, T, F>::type; 

隨着這您的select主要情況變爲:

template<typename Head, typename... Tail> 
struct select 
{ 
    using type = eval_if_t<Head::value, 
          Head, 
          select<Tail...>>; 
}; 

雖然反射,同樣可以與實現std::conditional_t和繼承:

template <typename Head, typename... Tail> 
struct select 
: std::conditional_t<Head::value, Head, select<Tail...>> 
{ }; 

而且,通常我們只是在結尾處的「其他人」的情況下,所以也許你會寫你的選擇是:

using T = select_t<cond<C1, int>, 
        cond<C2, float>, 
        double>; 

所以我建議正是如此寫你的基本情況:

template <typename T> 
struct select<T> 
{ 
    using type = T; 
}; 

template <bool B, typename T> 
struct select<cond<B, T>> 
{ 
    // last one had better be true! 
    static_assert(B, "!"); 
    using type = T; 
}; 

而且,你寫了std::select_t ...不要把它放在命名空間std中,把它放在你自己的命名空間中。

+0

另一種評論:否則「返回也是一個好主意,我甚至可以讓它返回一個默認值。但最後一個問題:沒有一個容納一對的cond 結構,我無法做到這一點嗎?即使使用2個可變參數模板參數?我也嘗試過,但無法使其工作。無論如何,再次感謝。 – sap

+1

@sap對於多個模板參數,它們都必須是類型。你必須傳遞'std :: true_type'而不是'true'。否則,實現是相同的 - 只需剝離包中的兩個參數而不是一個參數。 – Barry

+0

謝謝@Barry生病後來嘗試,作爲一個練習,非常感謝幫助。 – sap