c++variadic-templatesfoldsycl

Unpacking member type from std::tuple types


I have a collection of struts, each with a data_t member type (other members omitted):

struct A { using data_t = int; };
struct B { using data_t = double; };
struct C { using data_t = bool; };
// etc.

At compile-time, a selection of these are chosen to populate a composite type (also, with a corresponding data_t member):

#include <tuple>

using base_t = std::tuple<A, B, A, C>;

struct Foo : public base_t {
  using data_t = std::tuple<A::data_t, B::data_t, A::data_t, C::data_t>;
};

Currently I'm using CMake's configure_file to populate both the sequence of structs defining base_t, and the accompanying contents of Foo::data_t. Is it possible to instead derive the latter from base_t using variadic templates and/or fold expressions?

Using a fold expression, I can slightly simplify the construction of Foo::data_t, instead only needing to provide an integer sequence (of the same length):

#include <utility>

template<size_t... idx>
using helper = std:: tuple<
  typename std::tuple_element_t<idx, base_t>::data_t ...
>;

struct Bar : public base_t {
  using data_t = helper<0, 1, 2, 3>;
};

This, however, still requires the contents of Bar::data_t be manually/CMake configured (making it potentially error prone.) I had hoped that a suitably constructed std::index_sequence could be used to populate the helper template, but this produces a complier error (Intel C++ 2023.02)

struct Baz : public base_t {
  static constexpr auto indices{std::make_index_sequence<std::tuple_size_v<base_t>>};

  using data_t = helper<indices>;  // error: cannot convert std::index_sequence to size_t
};

I've read a bit about variadic templates, but couldn't figure out how they might be applied to a using statement. Am I missing a trick?

Thanks


Solution

  • Something along these lines:

    template <typename T>
    struct helper;  // left undefined
    
    template <typename... X>
    struct helper<std::tuple<X...>> {
      using type = std::tuple<typename X::data_t...>;
    };
    
    struct Bar : public base_t {
      using data_t = typename helper<base_t>::type;
    };
    

    Demo