拆分参数包

问题描述 投票:4回答:2

我想拆分模板参数包。像这样的东西。我怎么能这样做?

template< typename... Pack >
struct TypeB : public TypeA< get<0, sizeof...(Pack)/2>(Pack...) >
             , public TypeA< get<sizeof...(Pack)/2, sizeof...(Pack)>(Pack...) > 
{
};

以下是我为什么这个问题不重复的问题:我正在寻找一种通用的方法,将分组包传递给其他模板类时也能正常工作 - 如上所示。以及将其传递给函数。

c++ templates variadic-templates template-meta-programming template-inheritance
2个回答
1
投票

我想有很多方法可以做到这一点。

如果你至少可以使用C ++ 14,我建议使用decltype()std::tuple_cat()的强大功能如下:

(1)声明(没有定义的原因,因为通过decltype()使用了几个过载(和SFINAE启用/禁用)如下

template <std::size_t Imin, std::size_t Imax, std::size_t I, typename T>
std::enable_if_t<(Imin <= I) && (I < Imax), std::tuple<T>> getTpl ();

template <std::size_t Imin, std::size_t Imax, std::size_t I, typename>
std::enable_if_t<(I < Imin) || (Imax <= I), std::tuple<>> getTpl ();

当指数处于正确范围时,想法是返回std::tuple<T>,否则返回std::tuple<>

(2)定义一个辅助类来将std::tuple<Ts...>转换为TypeA<Ts...>

template <typename>
struct pta_helper2;

template <typename ... Ts>
struct pta_helper2<std::tuple<Ts...>>
 { using type = TypeA<Ts...>; };

(3)定义一个辅助类,它在元组中只连接正确范围内的类型

template <std::size_t, std::size_t, typename ... Ts>
struct pta_helper1;

template <std::size_t I0, std::size_t I1, std::size_t ... Is, typename ... Ts>
struct pta_helper1<I0, I1, std::index_sequence<Is...>, Ts...>
 : public pta_helper2<decltype(std::tuple_cat(getTpl<I0, I1, Is, Ts>()...))>
 { };

这个想法是连接std::tuple<>std::tuple<T>的序列,其中T类型是所请求范围内的类型;结果类型(pta_helper2的模板参数)是std::tuple<Us...>,其中Us...正是所请求范围内的类型。

(4)定义一个using类型,以更简单的方式使用前面的helper类

template <std::size_t I0, std::size_t I1, typename ... Ts>
using proTypeA = typename pta_helper1<
   I0, I1, std::make_index_sequence<sizeof...(Ts)>, Ts...>::type;

(5)现在你的TypeB变成了

template <typename ... Ts>
struct TypeB : public proTypeA<0u, sizeof...(Ts)/2u, Ts...>,
               public proTypeA<sizeof...(Ts)/2u, sizeof...(Ts), Ts...>
 { };

以下是完整的C ++ 14示例编译示例

#include <tuple>
#include <type_traits>

template <typename ...>
struct TypeA
 { };

template <std::size_t Imin, std::size_t Imax, std::size_t I, typename T>
std::enable_if_t<(Imin <= I) && (I < Imax), std::tuple<T>> getTpl ();

template <std::size_t Imin, std::size_t Imax, std::size_t I, typename>
std::enable_if_t<(I < Imin) || (Imax <= I), std::tuple<>> getTpl ();

template <typename>
struct pta_helper2;

template <typename ... Ts>
struct pta_helper2<std::tuple<Ts...>>
 { using type = TypeA<Ts...>; };

template <std::size_t, std::size_t, typename ... Ts>
struct pta_helper1;

template <std::size_t I0, std::size_t I1, std::size_t ... Is, typename ... Ts>
struct pta_helper1<I0, I1, std::index_sequence<Is...>, Ts...>
 : public pta_helper2<decltype(std::tuple_cat(getTpl<I0, I1, Is, Ts>()...))>
 { };

template <std::size_t I0, std::size_t I1, typename ... Ts>
using proTypeA = typename pta_helper1<
   I0, I1, std::make_index_sequence<sizeof...(Ts)>, Ts...>::type;


template <typename ... Ts>
struct TypeB : public proTypeA<0u, sizeof...(Ts)/2u, Ts...>,
               public proTypeA<sizeof...(Ts)/2u, sizeof...(Ts), Ts...>
 { };

int main()
 {
   using tb  = TypeB<char, short, int, long, long long>;
   using ta1 = TypeA<char, short>;
   using ta2 = TypeA<int, long, long long>;

   static_assert(std::is_base_of<ta1, tb>::value, "!");
   static_assert(std::is_base_of<ta2, tb>::value, "!");
 }

2
投票

使用std::tuple (C++11)std::index_sequence (C++14, but there are backports),标准库包含一切有效且有些方便拆分包。

template <class, class, class>
struct TypeBImpl;
template <std::size_t... N, std::size_t... M, class T>
struct TypeBImpl<std::index_sequence<N...>, std::index_sequence<M...>, T>
: TypeA<typename std::tuple_element_t<T, N>::type...>
, TypeA<typename std::tuple_element_t<T, M + sizeof...(N)>::type...>
{};

template <class... Ts>
struct TypeB
: TypeBImpl<
    std::make_index_sequence<sizeof...(Ts) / 2>,
    std::make_index_sequence<(sizeof...(Ts) + 1) / 2>,
    std::tuple<std::enable_if<1, Ts>...>
>
{};

为方便起见,我使用了一个中间库,它具有保持辅助类型以便在成员中重复使用的附加优点。


如果您不需要它,或者它在RTTI中的存在不方便,还有其他解决方案:

template <class T, std::size_t N, std::size_t... M>
auto TypeA_part_impl(std::index_sequence<M...>)
-> TypeA<typename std::tuple_element_t<T, N + M>::type...>;

template <bool tail, class... Ts>
using TypeA_part = decltype(TypeA_part_impl<
    std::tuple<std::enable_if<1, Ts>...>,
    tail * sizeof...(Ts) / 2>(
    std::make_index_sequence<(sizeof...(Ts) + tail) / 2>()));

template <class... Ts>
struct TypeB : TypeA_part<0, Ts...>, TypeA_part<1, Ts...>
{
};

我使用std::enable_if<1, T>作为传递任意类型信息的便捷工具,即使类型非常不规则也不能存储在std::tuple中,或者是不完整的。无需定义我自己的。

© www.soinside.com 2019 - 2024. All rights reserved.