【问题标题】:How to filter a variadic template pack by type derivation?如何按类型派生过滤可变参数模板包?
【发布时间】:2015-11-05 11:21:38
【问题描述】:

我有一个接收多种类型的模板类,接收到的每种类型都是两个选项之一的子类。 我想根据标识它们中的每一个的父类来不同地扩展它们。这相当于对可变参数模板参数实现“过滤”。

例如:

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。

【问题讨论】:

  • 您希望返回类型扩展到什么?你不能像那样返回多种类型。也许你想要std::tuple
  • 是的。元组。我打错了
  • 也许,您必须在派生类中声明一些typedef ... NearestBase; 才能遍历超类?

标签: c++ templates c++11 variadic-templates


【解决方案1】:

你可以这样做:

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • enable_if_else 看起来像std::conditional
    • 因为它的作用相同 - 我搜索了 std::conditional 之类的东西,但没有找到任何东西。所以我写了我自己的版本。我稍后会调整我的答案。
    • @PiotrSkotnicki 调整了我的代码。感谢您指出。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-23
    • 2015-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多