2016-12-18 2 views
11

Если у меня есть массив constexpr из N целых чисел, как его преобразовать в соответствующий constexpr std::tuple<...>?Как создать кортеж N T из массива T?

+2

Является ли ваш массив сырой массив или 'станд :: array' или что? –

+1

Зачем вам нужно «кортеж», когда у вас уже есть массив? – Barry

ответ

16

Вот возможная реализация для сырьевых массивов:

#include<functional> 

template<std::size_t... I, std::size_t N> 
constexpr auto f(const int (&arr)[N], std::index_sequence<I...>) { 
    return std::make_tuple(arr[I]...); 
} 

template<std::size_t N> 
constexpr auto f(const int (&arr)[N]) { 
    return f(arr, std::make_index_sequence<N>{}); 
} 

int main() { 
    constexpr int arr[] = { 0, 1, 2 }; 
    constexpr auto tup = f(arr); 
    static_assert(std::get<0>(tup) == 0, "!"); 
    static_assert(std::get<1>(tup) == 1, "!"); 
    static_assert(std::get<2>(tup) == 2, "!"); 
} 

Размер constexpr массива может быть выведен на compile- время, так что вам не нужно явно указывать.
Этот размер может быть использован внутри для создания набора индексов, чтобы получить элементы из массива и создать кортеж на лету.


Как упоминалось в комментариях, если вы хотите, чтобы обобщить немного больше и принимать как сырые массивы и std::array с, вы можете сделать это:

#include<functional> 
#include<array> 

template<std::size_t... I, typename U> 
constexpr auto f(const U &arr, std::index_sequence<I...>) { 
    return std::make_tuple(arr[I]...); 
} 

template<typename T, std::size_t N> 
constexpr auto f(const T (&arr)[N]) { 
    return f(arr, std::make_index_sequence<N>{}); 
} 

template<typename T, std::size_t N> 
constexpr auto f(const std::array<T, N> &arr) { 
    return f(arr, std::make_index_sequence<N>{}); 
} 

int main() { 
    constexpr int arr1[] = { 0, 1, 2 }; 
    constexpr auto tup1 = f(arr1); 
    static_assert(std::get<0>(tup1) == 0, "!"); 
    static_assert(std::get<1>(tup1) == 1, "!"); 
    static_assert(std::get<2>(tup1) == 2, "!"); 

    constexpr std::array<int, 3> arr2 = { 0, 1, 2 }; 
    constexpr auto tup2 = f(arr2); 
    static_assert(std::get<0>(tup2) == 0, "!"); 
    static_assert(std::get<1>(tup2) == 1, "!"); 
    static_assert(std::get<2>(tup2) == 2, "!"); 
} 
+1

Мне нравится этот ответ, у этого есть более чистый/более тонкий интерфейс. Благодаря! – Short

+0

Я объединил свой ответ с моим, чтобы покрыть как базовый массив, так и std :: array Short

+0

@Short Я бы не сделал так, как вы это делали для 'std :: array'. Если вы хотите, я могу обновить свой ответ, чтобы покрыть их. – skypjack

2

Преобразование массива в кортеж использует std::integer sequence, создавая индексы массивов во время компиляции, когда компилятор вызывает вспомогательную функцию для 0..N.

Вот код, который демонстрирует это. http://coliru.stacked-crooked.com/a/b2d6c6ca1f5dc635

//////////////////////////////////////////////////////////////////////////////////////////////////// 
// tuple_from_array 
namespace detail { 
template<typename T, std::size_t... Is> 
auto constexpr tuple_from_array(T const& arr, std::index_sequence<Is...>) 
{ 
    return std::make_tuple(arr[Is]...); 
} 

template<std::size_t N, typename V, typename T, std::size_t ...Is> 
auto constexpr array_from_container(T const& c, std::index_sequence<Is...>) 
{ 
    return std::array<V, N>{c[Is]...}; 
} 

} // ns detail 

template<typename T> 
auto constexpr tuple_from_array(T const& arr) 
{ 
    auto constexpr tup_size = std::tuple_size<std::decay_t<T>>::value; 
    return detail::tuple_from_array(arr, std::make_index_sequence<tup_size>{}); 
} 

template<typename T, std::size_t N> 
auto constexpr tuple_from_array(T const (&arr)[N]) 
{ 
    return detail::tuple_from_array(arr, std::make_index_sequence<N>{}); 
} 

// not safe 
template<std::size_t N, typename T> 
auto constexpr tuple_from_container(T const& c) 
{ 
    using V = typename T::value_type; 
    return tuple_from_array(detail::array_from_container<N, V>(c, std::make_index_sequence<N>{})); 
} 

редактировать: Я объединил skypjack @ 's ответ с моей собственной, чтобы покрыть основные массивы запрашиваются в комментариях. Я не могу повторно поставить это как мой собственный ответ в течение двух дней, хотя :(

+2

Публикация полезных вопросов и ответов всегда поощряется. Но ответ «код-дамп» не является воплощением качества. Я предлагаю вам отредактировать его с объяснением. – StoryTeller

+0

Как у этого есть «нулевые накладные расходы во время выполнения»? –

+0

Функции constexpr преобразуют массив в кортеж во время компиляции. Извините, я обновил пример и ссылку на код, чтобы создать экземпляр кортежа как значение constexpr. – Short

Смежные вопросы