Имеет ли С++ стандартный контейнер типа времени компиляции?

(Этот вопрос имеет ответ Nim, в котором упоминается boost:: mpl:: map.)

Есть ли в стандартном С++ контейнере времени компиляции, который может хранить типы?

Пример использования:

compiler::vector foo{char, short, long, long long};

template <int N>
void bar(foo[N] param){/*do something and return foo[N]*/}

Ответ 1

Настройте на Bérenger ответ, который положил меня на концепцию tuple. Но я считаю, что мы можем сделать лучше, даже сохраняя ссылки:

tuple foo<char&, short&, long&, long long&>;

template <int N>
void bar(tuple_element_t<N, decltype(foo)> param){}

На самом деле, если не планируется использовать foo за пределами этой функции, мы можем даже объявить его inline:

template <int N>
void bar(tuple_element_t<N, tuple<char&, short&, long&, long long&>> param){}

Ответ 2

В С++ 11 вы можете использовать std:: tuple: (отказ от ответственности: не проверен)

#include <tuple>
#include <type_traits>
std::tuple<char, short, long, long long> foo;

// reference type
template <int N>
void bar(decltype(std::get<N>(foo)) param){...}


// value type
template <int N>
void bar(std::remove_reference<decltype(std::get<N>(foo))>::type param)

Обратите внимание, что это не совсем то, что вы хотите, поскольку у вас будут либо только значения, либо ссылочные типы, даже если оба они смешаны в декларации кортежа foo.

Значение кортежа никогда не используется. Я думаю, что с оптимизацией компилятора foo фактически не будет инстанцироваться в объектном коде

Ответ 3

В качестве контейнера типа стандарт предоставляет вам std::tuple и - как прокомментировал bogdan - вы можете получить доступ к элементам типа с помощью std::tuple_element.

using foo = std::tuple<char, short&, const long&&, long long>;

template <int N>
typename std::tuple_element<N,foo>::type bar(){/*...*/}

Даже если std::tuple_element не существует, вы можете легко создать свой собственный:

/// We want a metafunction to accept an index N into our type list LIST
template <unsigned N, typename LIST> struct
tuple_element;

/// Specialization for the case where N==0
template <template <typename ...> class LIST_T,typename T,typename...ELMS> struct
tuple_element<0,LIST_T<T,ELMS...>> {
    using type = T; // just take the first type from the list
};

template <unsigned N, template <typename ...> class LIST_T,typename T,typename...ELMS> struct
tuple_element<N,LIST_T<T,ELMS...>> {
    /// fallback for N>0: delegate the result type recursively until N->0
    using type = typename tuple_element<N-1,LIST_T<ELMS...>>::type;
};

// create a convenience wrapper for the template
template <unsigned N, typename LIST> using
type_at = typename tuple_element<N, LIST>::type;

Теперь вы можете определить свой список типов, например. так:

using foo = std::tuple<char, short&, const long&&, long long>;

И вы можете легко получить доступ к элементам с помощью type_at<N, foo>:

static_assert(std::is_same< type_at<0,foo>, char>::value,"error");
static_assert(std::is_same< type_at<1,foo>, short&>::value,"error");
static_assert(std::is_same< type_at<2,foo>, const long&&>::value,"error");
static_assert(std::is_same< type_at<3,foo>, long long>::value,"error");

template <int N>
type_at<N,foo> bar(){/*...*/}