c++ 如何通过类型派生过滤可变参数模板包?

68bkxrlz  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(128)

我有一个接收多个类型的模板类,每个接收到的类型都是两个选项之一的子类。我想根据标识每个选项的父类来不同地扩展它们。这相当于在可变模板参数上实现“filter”。
举例来说,您可以:

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);

}


我使用C11,但如果需要,我可以转到C14。

uxhixvfz

uxhixvfz1#

你可以这样做:

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...>>>
{
};

字符串
或者使用std::tuple_cat

template <template <typename> class Pred, typename TUPLE>
struct Filter;

template <template <typename> class Pred, typename ... Ts> 
struct Filter<Pred, std::tuple<Ts...>>
{
    using type = decltype(std::tuple_cat(
           std::declval<std::conditional_t<Pred<Ts>::value,
                                           std::tuple<Ts>,
                                           std::tuple<>>>()...));
};


然后再进行以下操作:

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/Demo with std::tuple_cat系列

chhqkbe1

chhqkbe12#

如果你不介意使用元组作为返回值和参数,这可能是一个适合你的解决方案:

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);
}

字符串

相关问题