2014-11-25 12 views
5

Antworten here und here sind so ziemlich was ich brauche. Aber ich mag in der Lage sein, Sequenzen zu erzeugen, wie:Kompilierzeit Generate Integer-Sequenz mit einem ausgelassen

gen_seq<5, 2> // {0, 1, 3, 4} 
gen_seq<3, 0> // {1, 2} 
// optional behavior that would be useful for me: 
gen_seq<4, 4> // {0, 1, 2, 3} 

In den Beispielen I gen_seq verwendet, um eine Sequenz von 0 bis N-1 ohne I. zu erzeugen Dies ist nicht zwingend notwendig, würde ich auch in Ordnung sein mit gen_seq wobei N die Länge der Sequenz und I der fehlende Index oder andere Varianten sind.

Ich denke, das meiste des Problems ist bereits in den verknüpften Fragen beantwortet. Allerdings kann ich nicht wirklich sagen, wie man die Bedingung "leave this one out" für den zweiten Parameter einbaut.

Idealerweise würde ich gerne an C++ 11 Funktionen bleiben und C++ 14 vermeiden. Elegante und besonders lesbare Soulutions mit C++ 14 könnten aber auch sehr interessant sein.

Antwort

7

können Sie verwenden die folgenden:

#if 1 // Not in C++11 // make_index_sequence 
#include <cstdint> 

template <std::size_t...> struct index_sequence {}; 

template <std::size_t N, std::size_t... Is> 
struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {}; 

template <std::size_t... Is> 
struct make_index_sequence<0u, Is...> : index_sequence<Is...> { using type = index_sequence<Is...>; }; 

#endif // make_index_sequence 

namespace detail 
{ 
    template <typename Seq1, std::size_t Offset, typename Seq2> struct concat_seq; 

    template <std::size_t ... Is1, std::size_t Offset, std::size_t ... Is2> 
    struct concat_seq<index_sequence<Is1...>, Offset, index_sequence<Is2...>> 
    { 
     using type = index_sequence<Is1..., (Offset + Is2)...>; 
    }; 
} 

template <std::size_t N, std::size_t E> 
using gen_seq = typename detail::concat_seq<typename make_index_sequence<E>::type, E + 1, typename make_index_sequence<(N > E) ? (N - E - 1) : 0>::type>::type; 

static_assert(std::is_same<index_sequence<0, 1, 3, 4>, gen_seq<5, 2>>::value, ""); 
static_assert(std::is_same<index_sequence<1, 2>, gen_seq<3, 0>>::value, ""); 
static_assert(std::is_same<index_sequence<0, 1, 2, 3>, gen_seq<4, 4>>::value, ""); 

Live example

1

Immer großartig, Ihre Fragen niederzuschreiben.

Ich habe gerade herausgefunden, dass ich einfach die Divide and Conquer Methode benutzen kann und nicht von 0 bis N/2 und N/2 + 1 bis n erzeuge, sondern in einem ersten Schritt einfach von 0 bis I - 1 und von I + 1 bis N.

Dies kann ich mit der linearen oder auch log-Tiefe Generation Methode kombinieren. Jetzt fühle ich mich dumm zu fragen, aber zumindest bin ich nicht mehr fest.

2

Die einfache lineare Methode der Zahlenfolgen zu erzeugen trivially anpaßbar ist bestimmte Elemente auszuschließen, indem sie ein Spezialisierungen hinzufügen, die den Fall abdeckt, in dem das Element die eine wird ausgeschlossen:

#include <iostream> 

// general case, ignores X 

template <int N, int X, int... vals> 
struct gen_seq : gen_seq<N - 1, X, N - 1, vals...> { }; 

template <int X, int... vals> 
struct gen_seq<0, X, vals...> { static constexpr int values[] = { vals... }; }; 

// specialisations when vals has had X prepended: remove X 

template <int N, int X, int... vals> 
struct gen_seq<N, X, X, vals...> : gen_seq<N, X, vals...> { }; 

template <int... vals> 
struct gen_seq<0, 0, 0, vals...> : gen_seq<0, 0, vals...> { }; 

template <int X, int... vals> 
constexpr int gen_seq<0, X, vals...>::values[]; 

int main() { 
    for (auto i : gen_seq<5, 2>::values) std::cout << i << std::endl; // 0 1 3 4 
    for (auto i : gen_seq<3, 0>::values) std::cout << i << std::endl; // 1 2 
    for (auto i : gen_seq<4, 4>::values) std::cout << i << std::endl; // 0 1 2 3 
} 

Es ist möglicherweise nicht so effizient wie andere erweiterte Methoden, aber es ist am besten lesbar. Im Gegensatz zu Ihrer eigenen Antwort und den Jarod42-Modellen, erstellt dies keinen neuen Algorithmus, sondern baut einen neuen Algorithmus von Grund auf neu.