Search code examples
c++templatesvariadic-templatestemplate-meta-programming

C++ how to replace type in variadic template by its index


How can I replace 1 type from variadic template by its index? For example I have:

//-------------static_list-------------
template<class ...Elements>
struct static_list {};

struct execute_command<index, static_list<Commands...>> {
    static constexpr int value = execute_s<index + 1, static_list<Commands...>>::value;
}

and I want to rewrite it so in Commands it will replace type at for example index 5 with type variable<0, 0> like this:

struct execute_command<false, true, false, false, false, index, static_list<Commands...>> {
    static constexpr int value = execute_s<index + 1, static_list_replace<5, variable<0, 0>, Commands...>>::value;
}

I have tried it many different ways but nothing was working. For example:

//-------------static_list_replace-------------
template<std::size_t N, typename T, typename Tuple, class IndexSequence>
struct static_list_replace;

template<std::size_t N, typename T, typename Tuple, std::size_t... Idx>
struct static_list_replace<N, T, Tuple, std::index_sequence<Idx ...>> {
    using type = std::tuple<std::conditional_t<N == Idx, T, std::tuple_element_t<N, Tuple>>...>;
};

or

namespace detail {
    template<std::size_t N, typename T, typename Tuple, std::size_t... Idx>
    auto replace(std::index_sequence<Idx...>) ->
        std::tuple<std::conditional_t<N == Idx,
        T,
        std::tuple_element_t<N, Tuple>>...>;
}

template <std::size_t N, typename T, typename... Args>
using Replace = decltype(detail::replace<N, T, std::tuple<Args...>>
    (std::index_sequence_for<Args...>{}));

or I tried to get beginnig of the list and end without the one element and then pack it like static_list<list_beginning<index, Commands...>, element, list_ending<index, Commands...>>>

Nothing worked.


Solution

  • I suppose there are many ways...

    For example, given an helper class as slrh (Static List Replace Helper)

    template <std::size_t, typename...>
    struct slrh;
    
    template <std::size_t N, typename R, std::size_t ... Is, typename ... Ts>
    struct slrh<N, R, std::index_sequence<Is...>, Ts...>
     { using type = static_list<std::conditional_t<(N == Is), R, Ts>...>; };
    

    your static_list_replace can be simply written as follows

    template <std::size_t, typename R, typename SL>
    struct static_list_replace;
    
    template <std::size_t N, typename R, typename ... Ts>
    struct static_list_replace<N, R, static_list<Ts...>>
       : public slrh<N, R, std::make_index_sequence<sizeof...(Ts)>, Ts...>
     { };
    

    The following is a full compiling example

    #include <utility>
    #include <type_traits>
    
    template <typename ...>
    struct static_list
     { };
    
    template <std::size_t, typename...>
    struct slrh;
    
    template <std::size_t N, typename R, std::size_t ... Is, typename ... Ts>
    struct slrh<N, R, std::index_sequence<Is...>, Ts...>
     { using type = static_list<std::conditional_t<(N == Is), R, Ts>...>; };
    
    template <std::size_t, typename R, typename SL>
    struct static_list_replace;
    
    template <std::size_t N, typename R, typename ... Ts>
    struct static_list_replace<N, R, static_list<Ts...>>
       : public slrh<N, R, std::make_index_sequence<sizeof...(Ts)>, Ts...>
     { };
    
    template <int...>
    struct variable
     { };
    
    int main()
     {
       using T1 = static_list<char, short, int, long, long long>;
       using T2 = static_list<char, short, char, long, long long>;
       using T3 = typename static_list_replace<2u, char, T1>::type;
    
       using T4 = static_list_replace<4, variable<16, 16>,
                    static_list<char, short, int, long, long long>>::type;
       using T5 = static_list<char, short, int, long, variable<16, 16>>;
    
       static_assert( std::is_same_v<T2, T3> );
       static_assert( std::is_same_v<T4, T5> );
     }