Имеет ли С++ стандартный контейнер типа времени компиляции?
(Этот вопрос имеет ответ 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(){/*...*/}