如何从另一个元组实例创建一个元组实例,该实例仅静态选择满足特定类型规则的索引?

时间:2016-07-31 21:00:28

标签: c++ template-meta-programming

假设我有一个基类型和一些派生类型:

struct base {};
struct d1 : base {};
struct d2 : base {};

假设我创建了一个像:

这样的元组
std::tuple<double, d1, d2, int> t(1.0, d1(), d2(), 1);

是否可以使用元/运行时编程来生成:

template<typename T>
using my_predicate = std::is_base_of<base, T>;

std::tuple<d1, d2> t_derived = filter(t, my_predicate);

我已经看过堆栈交换的答案,可以让我定义新类型,但我还没想出如何从原始元组中选择运行时组件。堆栈交换帖子在这里:

https://codereview.stackexchange.com/questions/115740/filtering-variadic-template-arguments

1 个答案:

答案 0 :(得分:0)

您可以使用以下内容:

template <typename TupleOfIntegralConstant>
struct as_sequence;

template <typename ... Ts>
struct as_sequence<std::tuple<Ts...>> {
    using type = std::index_sequence<Ts::value...>;
};

template <template <typename> class Pred, typename Tuple, typename Seq>
struct make_filtered_sequence;

template <template <typename> class Pred, typename Tuple, std::size_t ... Is>
struct make_filtered_sequence<Pred, Tuple, std::index_sequence<Is...>>
{
    using type = typename as_sequence<decltype(std::tuple_cat(
           std::conditional_t<
             Pred<std::tuple_element_t<Is, Tuple>>::value,
             std::tuple<std::integral_constant<std::size_t, Is>>,
             std::tuple<>>{}...))>::type;
};

template <typename Tuple, std::size_t ... Is>
auto filter_impl(const Tuple& t, std::index_sequence<Is...>)
-> std::tuple<std::tuple_element_t<Is, Tuple>...>
{
    return {std::get<Is>(t)...};
}

template <template <typename> class Pred, typename Tuple>
auto filter(const Tuple& t)
{
    using filtered_seq = typename make_filtered_sequence<Pred, Tuple, std::make_index_sequence<std::tuple_size<Tuple>::value>>::type;

    return filter_impl(t, filtered_seq());
}

想法是创建一个过滤后的序列,然后对该序列使用std::tuple_element_tstd::get