Вдохновленный ответом Андрея Семашева ... нерекурсивная (и не std::tuple_element
) версия.
С учетом некоторой объявленной функции (не требующей определения: используются только внутри decltype()
)
template <std::size_t N, std::size_t I, typename, typename>
constexpr std::enable_if_t<(I == N), std::tuple<>> filter ();
template <std::size_t N, std::size_t I, typename T1, typename T2>
constexpr std::enable_if_t<(I < N), std::tuple<trans<T1, T2>>> filter ();
template <std::size_t N, typename ... Ts1, typename ... Ts2,
std::size_t ... Is>
constexpr auto getChain (std::tuple<Ts1...>, std::tuple<Ts2...>,
std::index_sequence<Is...>)
-> decltype(std::tuple_cat(filter<N, Is, Ts1, Ts2>()...));
Вы можете написать trans_chain_create
(_t
) следующим образом
template <typename T, typename ... Ts>
struct trans_chain_create
{
using Tpl1 = std::tuple<T, Ts...>;
using Tpl2 = std::tuple<Ts..., T>;
using IndS = std::make_index_sequence<sizeof...(Ts)+1u>;
using type = decltype(getChain<sizeof...(Ts)>
(std::declval<Tpl1>(), std::declval<Tpl2>(), IndS{}));
};
template <typename ... Args>
using trans_chain_create_t = typename trans_chain_create<Args...>::type;
Ниже приводится полная компиляция (достаточно C ++ 14), пример
#include <tuple>
#include <string>
#include <utility>
template <typename, typename>
class trans
{ };
class json
{ };
template <std::size_t N, std::size_t I, typename, typename>
constexpr std::enable_if_t<(I == N), std::tuple<>> filter ();
template <std::size_t N, std::size_t I, typename T1, typename T2>
constexpr std::enable_if_t<(I < N), std::tuple<trans<T1, T2>>> filter ();
template <std::size_t N, typename ... Ts1, typename ... Ts2,
std::size_t ... Is>
constexpr auto getChain (std::tuple<Ts1...>, std::tuple<Ts2...>,
std::index_sequence<Is...>)
-> decltype(std::tuple_cat(filter<N, Is, Ts1, Ts2>()...));
template <typename T, typename ... Ts>
struct trans_chain_create
{
using Tpl1 = std::tuple<T, Ts...>;
using Tpl2 = std::tuple<Ts..., T>;
using IndS = std::make_index_sequence<sizeof...(Ts)+1u>;
using type = decltype(getChain<sizeof...(Ts)>
(std::declval<Tpl1>(), std::declval<Tpl2>(), IndS{}));
};
template <typename ... Args>
using trans_chain_create_t = typename trans_chain_create<Args...>::type;
template <typename ... Args>
struct holder
{ using chain_type = trans_chain_create_t<Args...>; };
holder<std::string, int, float, std::string, json> h;
int main ()
{
using H = holder<std::string, int, float, std::string, json>;
using CT1 = typename H::chain_type;
using CT2 = std::tuple<trans<std::string, int>,
trans<int, float>,
trans<float, std::string>,
trans<std::string, json>>;
static_assert( std::is_same_v<CT1, CT2>, "!" );
}