2014-11-25 6 views
5

Le risposte here e here sono praticamente ciò di cui ho bisogno. Tuttavia, vorrei essere in grado di generare sequenze come:Tempo di compilazione genera la sequenza di numeri interi con uno escluso

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} 

Negli esempi ho usato gen_seq per generare una sequenza da 0 a N-1 senza I. Questo non è obbligatorio, avrei anche bene con gen_seq dove N è la lunghezza della sequenza e I l'indice mancante o altre varianti.

Penso che la maggior parte del problema sia già stata risolta nelle domande collegate. Tuttavia non riesco davvero a capire come incorporare la condizione "lasciare questo fuori" per il secondo parametro.

Idealmente, mi piacerebbe attenermi alle funzionalità di C++ 11 ed evitare C++ 14. Anche le animazioni eleganti e particolarmente leggibili che usano C++ 14 potrebbero essere anche molto interessanti.

risposta

7

È possibile utilizzare il seguente:

#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

Sempre fantastico per scrivere le vostre domande.

Ho appena capito che posso solo usare il metodo divide e conquista e generare non da 0 a N/2 e N/2 + 1 a n ma in una prima fase basta generare da 0 a I - 1 e da I + 1 a N.

Questo, posso combinare con il metodo di generazione lineare o anche profondità di registro. Ora mi sento stupido a chiedere, ma almeno non sono più bloccato.

2

Procedimento lineare semplice di generare sequenze intere è banalmente adattabile a parte gli articoli specifici, aggiungendo specializzazioni che copre il caso in cui l'articolo è escluso:

#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 
} 

Potrebbe non essere efficiente come altri metodi più avanzati, ma è il più leggibile. A differenza della tua risposta e di quella di Jarod42, questo non crea un nuovo algoritmo su quello preesistente, ma ne costruisce uno nuovo da zero.

Problemi correlati