2017-08-29 47 views
7

Czytałem this pytanie na SO.Inicjalizacja zestawu danych Czas kompilacji - ciąg Constexpr

Samo pytanie nie jest tak interesujące, ale zastanawiałem się, czy istnieje i jak zaimplementować rozwiązanie w czasie kompilacji.

odniesieniu do pierwszej sekwencji:

Wszystkie numery z wyjątkiem tych, które można podzielić przez 3.

Sekwencja powinno być coś takiego:

[1, 2, 4, 5, 7, 8, 10, 11, 13, 14, ...] 

przez indukcję , Znalazłem wzór matematyczny dla tej sekwencji:

f(0) = 0; 
f(x > 0) = floor[(3x - 1)/2]; 

Więc zostały wdrożone w C++ constexpr funkcję, która generuje i-th numer w kolejności:

#include <type_traits> 

template <typename T = std::size_t> 
constexpr T generate_ith_number(const std::size_t index) { 
    static_assert(std::is_integral<T>::value, "T must to be an integral type"); 

    if (index == 0) return 0; 
    return (3 * index - 1)/2; 
} 

Teraz chciałbym wygenerować "kompilacji czasu tablicy/sekwencji", który przechowuje pierwsze N-ty numer sekwencji.

Struktura powinno być coś jak:

template <typename T, T... values> 
struct sequence {}; 

template <typename T, std::size_t SIZE> 
struct generate_sequence {}; // TODO: implement 

pytania (więcej niż jedna, ale związane między nimi):

1) Jak wdrożyć tego rodzaju integer_sequence?

2) Czy jest możliwe zbudowanie std::array z tego integer_sequence podczas kompilacji?

Odpowiedz

12

1) Jak wdrożyć tego rodzaju integer_sequence?

template <std::size_t... Is> 
constexpr auto make_sequence_impl(std::index_sequence<Is...>) 
{ 
    return std::index_sequence<generate_ith_number(Is)...>{}; 
} 

template <std::size_t N> 
constexpr auto make_sequence() 
{ 
    return make_sequence_impl(std::make_index_sequence<N>{}); 
} 

2) Czy możliwe jest zbudowanie std::array z tego integer_sequence w czasie kompilacji?

template <std::size_t... Is> 
constexpr auto make_array_from_sequence_impl(std::index_sequence<Is...>) 
{ 
    return std::array<std::size_t, sizeof...(Is)>{Is...}; 
} 

template <typename Seq> 
constexpr auto make_array_from_sequence(Seq) 
{ 
    return make_array_from_sequence_impl(Seq{}); 
} 

Zastosowanie:

int main() 
{ 
    constexpr auto arr = make_array_from_sequence(make_sequence<6>()); 
    static_assert(arr[0] == 0); 
    static_assert(arr[1] == 1); 
    static_assert(arr[2] == 2); 
    static_assert(arr[3] == 4); 
    static_assert(arr[4] == 5); 
    static_assert(arr[5] == 7); 
} 

live example on wandbox.org

+1

Z dedukcjami konstruktora C++ 17, 'std :: array {Is ...};' może być uproszczone do 'std :: array {Is ... }; '. – metal

1

Jest to dość proste, aby wygenerować tablicę używając kodu dość prosty w ostatnim C++:

template<typename T, T N> 
constexpr auto make_constexpr_array(std::integral_constant<T, N>) 
{ 
    std::array<int,N> result = {}; 
    for (int i = 0; i < N; ++i) 
     result[i] = (3*i - 1)/2; 
    return result; 
} 

int main() 
{ 
    constexpr auto arr = make_constexpr_array(std::integral_constant<int, 6>{}); 
    static_assert(arr[0] == 0); 
    static_assert(arr[1] == 1); 
    static_assert(arr[2] == 2); 
    static_assert(arr[3] == 4); 
    static_assert(arr[4] == 5); 
    static_assert(arr[5] == 7); 
}