2015-12-09 18 views
6

Desidero creare un array 2D popolato da alcune funzioni note con senza sovraccarico di runtime.Inizializzazione di un array 2D semplice con una determinata funzione in fase di compilazione

Per avere un esempio, supponiamo che una funzione f(x, y) = 10 * y + x, cerchiamo x essere in {1, 2, 3} e y in {4, 5, 6}. Voglio creare una matrice 2D con contenuti

41 42 43 
51 52 53 
61 62 63 

Ora, il modo più semplice per andare è solo hard-code i valori direttamente nelle mie fonti. Ed è davvero appropriato per il mio compito, quindi la domanda è solo per curiosità.

Vorrei creare un metafunc e una struttura possedere una sorta di magia nera, che mi consente di definire una matrice di determinati set di valori per x e . Come questo:

template<int X> struct Func { 
    template<int Y> struct over { 
    static const int value = 10 * Y + X; // f(x, y) 
    }; 
}; 

template<int... args1> struct Rows { 
    template<int... args2> struct Cols { 
    static const int data[sizeof...(args1)][sizeof...(args2)]; 
    }; 
}; 

template<int... args1> 
template<int... args2> 
const int Rows<args1...>::Cols<args2...>::data[sizeof...(args1)][sizeof...(args2)] = { 
    { Func<args1>::over<args2>::value... } // This does not do what I want :(
              // Need some black magic here 
}; 

// Here is my precious table 
const auto& table = Rows<1, 2, 3>::Cols<4, 5, 6>::data; 

se stampo valori dalla tabella, ho questo:

41 52 63 
0 0 0 
0 0 0 

ho capito quello che sta succedendo, il termine Func<args1>::over<args2>::value ha due confezioni di parametri in esso, args1 e args2, così l'applicazione ... su di esso espanderli contemporaneamente, e ho solo 3 membri invece di 9.

Se hai raggiunto così lontano, hai già capito quello che voglio. Quindi la domanda è: come faccio? Come applicare i puntini di sospensione separatamente a entrambi i pacchetti di parametri in modo che possa avere una combinazione cartesiana nell'inizializzatore? O forse ci sono altri modi per farlo?

Sono a conoscenza di this answer e that answer. Utilizzano std::array invece di un semplice array, quindi prima costruiscono array 1D e quindi inizializzano l'array 2D con un numero di array 1D. Ma se ho capito bene, questa inizializzazione deve essere eseguita in runtime. Voglio evitarlo. Tuttavia, non ho obiezioni contro std::array. Suppongo che con un compilatore appropriato siano veloci quanto semplici array.

A proposito, ecco il mio possible solution utilizzando il constexpr generalizzato da C++ 14 e una domanda a riguardo. Anche le idee su come risolvere l'attività con constexpr da C++ 11 sono benvenute.

+0

iterare tutta la riga prima, e poi scorrere attraverso colonne. – VermillionAzure

+0

Sono assolutamente orribile, ma il modo in cui è scritto in questo momento è "ambiguo". La struttura è nidificata, ma non ha l'iterazione template annidata. Quindi magari provare ad avere il tipo specificato per la struct di primo livello e poi farne un altro con il secondo livello strict ancora con un elenco variadic. Quindi creare un'istanza di un caso specifico con il caso istanziato di livello superiore. – VermillionAzure

+0

Hai davvero bisogno di un array 2d?Hai appena trovato la soluzione per un array 1d –

risposta

1

L'unico modo ho trovato è quello di separare i pacchi parametri da virgole ed espandere uno di essi, e poi per espandere l'altro dall'esterno:

#include <array> 
#include <utility> 

using namespace std; 

template<class T, T Y, T... Xs> 
constexpr array<T, sizeof...(Xs)> a1{10*Y+Xs...}; 

template<class T, T... Xs, T... Ys> 
constexpr auto a2(integer_sequence<T, Xs...>, integer_sequence<T, Ys...>) { 
    return array<array<T, sizeof...(Xs)>, sizeof...(Ys)>{a1<T, Ys, Xs...>...}; 
} 

array<array<int, 3>, 3> table(a2(
    integer_sequence<int, 1, 2, 3>(), 
    integer_sequence<int, 4, 5, 6>() 
)); 

Il risultato asm è questo:

table: 
     .long 41 
     .long 42 
     .long 43 
     .long 51 
     .long 52 
     .long 53 
     .long 61 
     .long 62 
     .long 63 

Code in Compiler Explorer

+0

Grazie per la risposta, ma funziona solo in C++ 14, non in C++ 11, mentre ho già una soluzione per C++ 14. – Mikhail

Problemi correlati