简体   繁体   中英

Convert scalar + std::array + std::tuple into a big tuple

Consider the following code:

template <class Scalar, class Array, class Tuple>
class Test {};

where Array is a std::array , and Tuple is a std::tuple . In this class, I will have a lot of SFINAE, and I would like to create a big tuple called Types that will contain the complete list of types. This will allow me to test some conditions with variadic lists.

So the challenge is to create a type that will have the following behaviour. If:

  • Scalar = int
  • Array = std::array<double, 3>
  • Tuple = std::tuple<char, float, std::string>

Then:

  • Types = std::tuple<int, double, double, double, char, float, std::string>

which is the concatenation of the internal data of the Scalar , Array and Tuple .

How to do that ?

This seems to work:

template<typename T1, typename T2>
struct concat_tuples;

template<typename... T1, typename... T2>
struct concat_tuples<std::tuple<T1...>, std::tuple<T2...>>
{
    using type = std::tuple<T1..., T2...>;
}; 

// n_tuple<int, 3>::type == std::tuple<int, int, int>
template<typename T, size_t n>
struct n_tuple;

template<typename T>
struct n_tuple<T, 0> 
{
    using type = std::tuple<>;
};

template<typename T, size_t n>
struct n_tuple
{
    using type = typename concat_tuples<
                    typename n_tuple<T, n-1>::type, 
                    std::tuple<T>
                >::type;
};

template <class Scalar, class Array, class Tuple>
struct Test;

template <class Scalar,  typename T, size_t n, typename... Ts>
struct Test<Scalar, std::array<T, n>, std::tuple<Ts...>>
{
    using type = typename concat_tuples<
                    typename concat_tuples<
                        std::tuple<Scalar>, 
                        typename n_tuple<T, n>::type
                    >::type, 
                    std::tuple<Ts...>
                >::type;
};

Live demo here .

Use a partial specialization to deduce the types, and Xeo's tuple_cat comment to put them together ( Live at Coliru :

template <typename ArrayType, std::size_t ArraySize, typename... Fields>
struct ArrayTuple : ArrayTuple<ArrayType, ArraySize-1, ArrayType, Fields...> {};
template <typename ArrayType, typename... Fields>
struct ArrayTuple<ArrayType, 0, Fields...> {
    using type = std::tuple<Fields...>;
};

template <typename, typename, typename> class Test;

template <typename Scalar, typename ArrayType, std::size_t ArraySize, typename... Fields>
class Test<Scalar, std::array<ArrayType, ArraySize>, std::tuple<Fields...>> {
public:
    // Modified tuple_cat code from Xeo's comment:
    using Tuple = std::tuple<Fields...>;
    using Types = decltype(
      std::tuple_cat(std::tuple<Scalar>(),
                     typename ArrayTuple<ArrayType, ArraySize>::type(),
                     std::declval<Tuple>()));
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM