代码之家  ›  专栏  ›  技术社区  ›  greywolf82

在层次结构中反转变量模板参数

  •  1
  • greywolf82  · 技术社区  · 5 年前

    我现在有一个使用类型列表的类:

    template<class AbstractF, template<class, class > class Creator, class TList>
    class A: public B<typename Reverse<TList>::Result, Creator, AbstractF> {
    };
    

    我正试图使代码更易于c++11使用可变模板参数替换typelist。

    template<class AbstractF, template<class, class > class Creator, class TList...>
    class A: public B<Creator, AbstractF, TList...> { //<---how to reverse here?
    };
    

    问题是:如何反转变量列表?看看其他问题,我看到了 std::tuple ,但在本例中,我无法理解如何“解包”,因为变量参数不是简单模板化函数的一部分,而是用作类层次结构中的参数。

    1 回复  |  直到 5 年前
        1
  •  2
  •   Evg    5 年前

    如果包中的所有类型都是不同的,则可以计算 index 从类型本身。剩下的就是 N - 1 - index '包装中的第种类型:

    template<std::size_t index, class... Ts>
    using Nth_type = std::tuple_element_t<index, std::tuple<Ts...>>;
    
    template<class S, class... Ts>
    inline constexpr std::size_t type_index = 0;
    
    template<class S, class T, class... Ts>
    inline constexpr std::size_t type_index<S, T, Ts...> = 
        std::is_same_v<S, T> ? 0 : 1 + type_index<S, Ts...>;
    
    template<class T, class... Ts>
    using Reverser = Nth_type<sizeof...(Ts) - 1 - type_index<T, Ts...>, Ts...>;
    

    简单示例:

    template<class... Ts>
    class B;
    
    template<class... Ts>
    using RB = B<Reverser<Ts, Ts...>...>;   // two pack expansions here
    
    static_assert(std::is_same<RB<>, B<>>());
    static_assert(std::is_same<RB<int>, B<int>>());
    static_assert(std::is_same<RB<int, float, double>, B<double, float, int>>());
    

    如果允许包包含相同的类型,此技巧将不起作用。

    这个代码使用了一些C++ 14/17的特性。变量模板不是C++ 11的一部分,所以 type_index 必须以不同的方式实施。 Here 是一个可能的实现。

        2
  •  0
  •   Jarod42    5 年前

    我正试图使代码更易于c++11用可变模板参数替换typelist

    如果使用旧的类型列表方式(类型的链接列表) 然后在C++ 11中,甚至可以使用未包装的变量模板参数,或者在内部填充变量模板参数。 std::tuple 或类似的。

    解包方式对操作(转换、跳头、连接)有限制,可能需要先使用打包方式。

    对于重新排序,包装方式可能是:

    template <typename TypeList, typename Seq> struct ReverseImpl;
    
    template <typename TypeList, std::size_t ... Is>
    struct ReverseImpl<TypeList, std::index_sequence<Is...>>
    {
        using type = std::tuple<typename std::tuple_element<sizeof...(Is) - 1 - Is, TypeList>::type...>;
    };
    
    
    template <typename TypeList> struct Reverse
    {
        using Result =
            typename ReverseImpl<TypeList,
                                 std::make_index_sequence<std::tuple_size<TypeList>::value>>::type;
    };
    

    注: std::index_sequence / std::make_index_sequence 是C++ 14,但是可以在C++ 11中实现。

    可能的用法是:

    template <template<class, class > class Creator, class AbstractF, typename TypeList>
    struct BUnpack;
    
    template<template<class, class > class Creator, class AbstractF, typename ... Ts>
    class BUnpack<Creator, AbstractF, std::tuple<Ts...>>
    {
        using type = B<Creator, AbstractF, Ts...>;
    };
    
    template<class AbstractF, template<class, class > class Creator, typename ... Ts>
    class A: public BUnpack<Creator, AbstractF, typename Reverse<std::tuple<Ts...>>::Result>::type {
    };