2015-11-05 58 views
2

我有一個模板類接收多種類型,每種類型收到的是兩個選項之一的子類。 我想根據識別每個父類的不同來擴展它們。這相當於在可變參數模板參數上實現「過濾」。如何通過類型派生篩選可變模板包?

例如:

class A{}; 
class B{}; 

template<class... C> 
struct F{ 
    std::tuple<types_derived_by<A, C>...> fn(types_subclassing<B, C>...){} 
}; 

的types_derived_by模板函數應該產生在C的所有類型的從A衍生,或B.

例如一個可變參數模板包:

struct DA : public A{}; 
struct DB : public B{}; 
int main(){ 
    F<DA, DB> f; 
    //f has a member function: DA fn(DB); 

} 

我正在使用C++ 11,但如果有必要,我可以移動到C++ 14。

+1

你期望返回類型擴展到什麼?你不能像這樣返回多種類型。也許你想要一個'std :: tuple'? – TartanLlama

+0

是的。元組。我輸錯了 – dvicino

+0

也許,你必須在派生類中聲明一些'typedef ... NearestBase;'來遍歷超類? –

回答

4

你可以這樣做:

template <template <typename> class Pred, typename TUPLE, typename Res = std::tuple<>> 
struct Filter; 

template <template <typename> class Pred, typename Res> 
struct Filter<Pred, std::tuple<>, Res> 
{ 
    using type = Res; 
}; 

template <template <typename> class Pred, typename T, typename ... Ts, typename ... TRes> 
struct Filter<Pred, std::tuple<T, Ts...>, std::tuple<TRes...>> : 
    Filter<Pred, 
      std::tuple<Ts...>, 
      std::conditional_t<Pred<T>::value, 
           std::tuple<TRes..., T>, 
           std::tuple<TRes...>>> 
{ 
}; 

然後:

class A {}; 
template <typename T> 
using is_base_of_A = std::is_base_of<A, T>; 

class B {}; 
struct DA : public A{}; 
struct DB : public B{}; 
struct DA1 : public A{}; 

static_assert(std::is_same<std::tuple<DA, DA1>, 
          Filter<is_base_of_A, std::tuple<DA, DB, DA1>>::type>::value, 
       "unexpected"); 

Demo

0

如果你不介意使用元組作爲返回值和參數,這可能是一個解決方案爲你:

template <typename Base, typename...T> 
struct base_filter; 

template <typename Base> 
struct base_filter<Base> 
{ 
    using type = std::tuple<>; 
}; 

template <typename Base, typename T1> 
struct base_filter<Base, T1> 
{ 
    using type = typename std::conditional_t<std::is_base_of<Base, T1>::value, std::tuple<T1>, std::tuple<>>; 
}; 

template <typename Base, typename T1, typename...T> 
struct base_filter<Base, T1, T...> 
{ 
    using type = decltype(std::tuple_cat(base_filter<Base, T1>::type(), base_filter<Base, T...>::type())); 
}; 


//########################################################### 

class A {}; 
class B {}; 


template<class...C> 
struct F { 
    typename base_filter<A, C...>::type fn(typename base_filter<B, C...>::type){} 
}; 

struct DA : public A {}; 
struct DB : public B {}; 
struct DA1 : public A {}; 
struct DA2 : public A {}; 
struct DB1 : public B {}; 
struct DB2 : public B {}; 


int main() { 
    std::tuple<DB> b; 
    F<DA, DB> f1; 
    std::tuple<DA> a = f1.fn(b); 

    std::tuple<DB1, DB2> bb; 
    F<DB1, DA1, DB2, DA2> f2; 
    std::tuple<DA1, DA2> aa = f2.fn(bb); 
} 
+0

'enable_if_else'看起來像'std :: conditional' –

+0

因爲它的確如此 - 我搜索了類似'std :: conditional'的東西,但是沒有找到任何東西。所以我寫了我自己的版本。我稍後會調整我的答案。 –

+0

@PiotrSkotnicki調整我的代碼。感謝您指出。 –