2013-09-25 23 views
11

Sto cercando di creare una tabella di ricerca di coordinate, qualcosa come:Tabella di ricerca con constexpr

int a[n][2] = {{0,1},{2,3}, ... } 

Per una data n, da creare in fase di compilazione. Ho iniziato a guardare in constexpr, ma è sembra come una funzione che restituisce un constexpr std::vector<std::array <int, 2> > non è un'opzione, come ottengo:

invalid return type 'std::vector<std::array<int, 2ul> >' of constexpr function 

Come può creare una tale varietà tempo di compilazione?

+1

'std :: VECTOR' non è un tipo letterale e quindi non può essere usato in C++ 11 'constexpr'. Il tipo 'array' di C++ 11 manca degli accessors' constexpr' e quindi ha anche un uso limitato nelle funzioni 'constexpr'. Se non si dispone del supporto del lib/compiler C++ 1y, suggerisco di utilizzare un tipo di array personalizzato. – dyp

+0

@DyP - potresti mostrare un esempio? – nbubis

+0

Sarebbe più utile se hai aggiunto alcuni dettagli su cosa vuoi fare;) – dyp

risposta

15

Prima farò il dump del codice, aggiungendo riferimenti e commenti dove necessario/appropriato in seguito. Lascia un commento se il risultato è un po 'vicino a quello che stai cercando.

Indici trucco per pacchetto di espansione (richiesto qui per applicare il generatore), da Xeo, da this answer, modificato per utilizzare std::size_t anziché unsigned.

#include <cstddef> 

// by Xeo, from https://stackoverflow.com/a/13294458/420683 
template<std::size_t... Is> struct seq{}; 
template<std::size_t N, std::size_t... Is> 
struct gen_seq : gen_seq<N-1, N-1, Is...>{}; 
template<std::size_t... Is> 
struct gen_seq<0, Is...> : seq<Is...>{}; 

funzione di generatore:

#include <array> 

template<class Generator, std::size_t... Is> 
constexpr auto generate_array_helper(Generator g, seq<Is...>) 
-> std::array<decltype(g(std::size_t{}, sizeof...(Is))), sizeof...(Is)> 
{ 
    return {{g(Is, sizeof...(Is))...}}; 
} 

template<std::size_t tcount, class Generator> 
constexpr auto generate_array(Generator g) 
-> decltype(generate_array_helper(g, gen_seq<tcount>{})) 
{ 
    return generate_array_helper(g, gen_seq<tcount>{}); 
} 

Esempio di utilizzo:

// some literal type 
struct point 
{ 
    float x; 
    float y; 
}; 
// output support for `std::ostream` 
#include <iostream> 
std::ostream& operator<<(std::ostream& o, point const& p) 
{ return o << p.x << ", " << p.y; } 

// a user-defined generator 
constexpr point my_generator(std::size_t curr, std::size_t total) 
{ 
    return {curr*40.0f/(total-1), curr*20.0f/(total-1)}; 
} 

int main() 
{ 
    constexpr auto first_array = generate_array<5>(my_generator); 
    constexpr auto second_array = generate_array<10>(my_generator); 

    std::cout << "first array: \n"; 
    for(auto p : first_array) 
    { 
     std::cout << p << '\n'; 
    } 
    std::cout << "========================\n"; 

    std::cout << "second array: \n"; 
    for(auto p : second_array) 
    { 
     std::cout << p << '\n'; 
    } 
} 
+1

Wow - Questo è un sacco di codice! È davvero il modo più breve per farlo? – nbubis

+0

@nbubis Questa è una soluzione molto generale. Se si restringe/si specifica in modo più preciso ciò che si desidera, potrebbe esserci una soluzione meno dettagliata. – dyp

+0

Penso che l'esempio di utilizzo sia esattamente quello che sto cercando, ma quello è sicuramente un sacco di codice extra :) – nbubis

-1

Cosa succede ad usare GNU gperf o qualche altro programma di utilità di generazione del codice?

+1

Ciao. Saresti in grado di usare gperf per inizializzare un vettore in fase di compilazione? E se come? –

14

Con C++ 14, non è necessario troppa magia di template. Ecco un esempio di come una tabella di ricerca per f(x) = x^3 con la prima coordinata è il valore x e la seconda coordinata essendo il valore f(x):

#include <iostream> 

template<int N> 
struct Table 
{ 
    constexpr Table() : values() 
    { 
     for (auto i = 0; i < N; ++i) 
     { 
      values[i][0] = i; 
      values[i][1] = i * i * i; 
     } 
    } 
    int values[N][2]; 
}; 

int main() { 
    constexpr auto a = Table<1000>(); 
    for (auto x : a.values) 
     std::cout << "f(" << x[0] << ") = " << x[1] << '\n'; 
} 
+0

Davvero bello !! Tanto C++ 1x da imparare .. – nbubis

+0

Qual è il significato di: ': values ​​()' in 'constexpr Table(): values ​​()'? Inizializza a zero o qualcosa del genere? – Jonas

+0

e Jonas Sì, inizializza a zero, cosa necessaria perché C++ deve avere un valore di compilazione-const. Sarà impostato in seguito nel costruttore ma questo è difficile da tracciare dal compilatore – IceFire