10

我想要一個模板可以根據某些條件從兩種類型中進行選擇。例如。在T1和T2之間選擇C++類型的特徵

struct Base {}; 

template <typename T1, typename T2> 
struct test 
{ 
    // e.g. here it should select T1/T2 that is_base_of<Base> 
    typename select_base<T1, T2>::type m_ValueOfBaseType; 
}; 

當然通過條件的select_base中(使它通用)是有用的,但硬編碼的解決方案更容易,以及良好。

下面是我試過的樣品溶液,但它總是選擇T1:http://ideone.com/EnVT8

的問題是如何實現select_base模板。

+0

你的問題是什麼? – Nawaz

+0

你的問題不清楚。你想從兩種類型'T1'或'T2'中選擇基本類型,例如,如果'T1'從'T2'派生,那麼輸出類型應該是'T2'。或者你想選擇從第三種類型派生的類型,比如'base'? – Nawaz

+0

@Nawaz:從鏈接的ideone中,我會說'Base'是固定的,他想選擇從其中導出的'T1'或'T2'中的任何一個。 –

回答

6

C++ 14(及以後):

template <typename T, typename U> 
struct select_base: 
    std::conditional_t<std::is_base_of<T, Base>::value, T, U> {}; 

在同樣,可以改爲使用:

template<typename T, typename U> 
using select_base = std::conditional_t<std::is_base_of_v<T,Base>, T, U>; 

這兩種方法之間的差異可以被觀察到時你使用它們。例如,在第一種情況下,如果您必須使用::type,而在第二種情況下,您不需要。如果任何依賴類型涉及第一種方法的使用,則還必須使用typename來協助編譯器。第二種方法沒有所有這些噪音,因此優於其他方法。

另外,請注意,您也可以在C++ 11中編寫類似的類型別名。


C++ 11

template <typename T, typename U> 
struct select_base: 
    std::conditional<std::is_base_of<T, Base>::value, T, U>::type {}; 
//    ^          ^~~~~~ 

C++ 98

條件是很容易:

template <typename bool, typename T, typename U> 
struct conditional { typedef T type; }; 

template <typename T, typename U> 
struct conditional<false, T, U> { typedef U type; }; 

is_base_of稍微複雜一點,Boost中有一個實現,我不會在這裏重現。

之後,請參閱C++ 11。

+0

是的,這是通用的,運作良好,謝謝!我完全忘記了非類型模板參數。 – queen3

+0

'if_'模板已被標準化爲'std :: conditional'。 http://en.cppreference.com/w/cpp/types/conditional – NicholasM

+0

@NicholasM:答覆已更新。 –

18

如果您使用的std::conditional代替if_類模板由@Matthieu在他的回答中實現,那麼你的解決方案將減少到這一點:

template <typename T, typename U> 
struct select_base 
{ 
    typedef typename std::conditional<std::is_base_of<T, Base>::value, T, U>::type base_type; 
}; 

或者簡單:

template <typename T, typename U> 
struct select_base : std::conditional<std::is_base_of<T, Base>::value, T, U> {}; 

看起來甚至更好。

這兩種解決方案之間的區別是,在第一個解決方案你嵌套類型給予程序員友好的名字,因爲我已經給它base_type,而在第二個解決方案的嵌套式只是type這看起來不像程序員友好。

注意,在上述兩種解決方案,你已經使用嵌套的類型或者select_base<T,U>::base_type(第一溶液)或select_base<T,U>::type(在因爲第二個解決方案—,如果你已經使用typename爲你寫你自己的問題本身

不過,如果你代替使用模板的別名,定義爲:

template<typename T, typename U> 
using base_type = typename std::conditional<std::is_base_of<T, Base>::value, T, U>::type; 

那麼你可以使用base_type<T,U>沒有任何嵌套型和typename as:

template <typename T1, typename T2> 
struct test 
{ 
    //typename select_base<T1, T2>::type m_ValueOfBaseType; //ugly! 

    base_type<T1, T2> m_ValueOfBaseType; //better 
}; 

希望有幫助。

+0

啊謝謝,我無法把頭圍繞在這個名字上,這個名字太奇怪了:x(另外,除非你在這裏缺少'typedef typename')。 –

+0

@MatthieuM .:哦,只是忘了那部分。 – Nawaz

+0

是的,感謝提示,在Matthieu的回答之後,我確信我會在type_traits中找到類似的東西,當然它在那裏。我想我必須先閱讀文檔,因爲重新發明輪子很有趣,但並不富有成效。 – queen3

相關問題