2013-03-21 22 views
5

Ho creato una classe simile a una matrice, ma anziché contenere i dati nel programma stesso, esegue il flusso del byte da un file (per ridurre l'impatto della RAM). Ora ho tutto questo lavoro, ma il programmatore deve definire la classe usando la seguente:Generazione dei parametri del modello in fase di compilazione

#define CreateReadOnlyBlock(name, location, size, ...)   \ 
template<>              \ 
const unsigned int ReadOnlyBlock<location, size>::Data[]  \ 
    __asm__(".readonly__" #location "__" #name)    \ 
    = { __VA_ARGS__ };           \ 
ReadOnlyBlock<location, size> name; 

Esempio:

//A read only array of {0, 1, 2, 3} 
CreateReadOnlyBlock(readOnlyArray, 0, 4, 0, 1, 2, 3); 

Si noti che questo è per un processore embedded, e la direttiva asm passa attraverso uno strumento nell'assemblatore per creare il file di sola lettura.

Quindi, ecco la mia domanda: come posso eliminare le variabili "posizione" e "dimensione"? Detesto che il programmatore debba scriverle manualmente e preferirebbe molto un modo per generarle in fase di compilazione. Così, invece di programmatore dover digitare:

//A read only array at location 0 of {0, 1, 2, 3} 
CreateReadOnlyBlock(readOnlyArray1, 0, 4, 0, 1, 2, 3); 
//A read only array at location 4 of {4, 5, 6, 7} 
CreateReadOnlyBlock(readOnlyArray2, 4, 4, 4, 5, 6, 7); 

Potrebbero basta digitare:

CreateReadOnlyBlock(readOnlyArray1, 0, 1, 2, 3); 
CreateReadOnlyBlock(readOnlyArray2, 4, 5, 6, 7); 

E le costanti appropriate sarebbe generato. Fondamentalmente sto cercando un modo per generare e posizionare queste costanti in base alle definizioni precedenti in fase di compilazione. C++ 11 è un gioco leale, non ne ho molta familiarità (qualcosa con constexpr sembra plausibile?). Inoltre, C-Preprocessor va bene anche se non lo rende più brutto di quello che è già. È possibile?

EDIT per chiarezza:

Nella classe ReadOnlyBlock c'è questo metodo:

template<const int _location, const int _size> class ReadOnlyBlock 
    { 
     ... 
     unsigned int operator[] (size_t index) 
     { 
      return LoadFromROM(index + _location); 
     } 
    } 

Esiste un'interdipendenza intrinseca tra la variabile posizione e il file ROM che non riesco a pensare a come rompere. I do hanno il controllo completo sulla catena di strumenti, tuttavia, ma ho bisogno di un modo per passare allo strumento assemblatore come costruire il file e indicare al codice C++ dove i blocchi si trovano nel file.

Un altro EDIT:

Il file ed i suoi blocchi possono essere abbastanza grande, per quanto 1k parole, così un sacco di magia preprocessore potrebbe crollare, dato che. Inoltre, grazie a tutti per l'aiuto finora!

+0

Il '# location' nella parte '__asm__' lo sta davvero uccidendo. Ne hai davvero bisogno o saresti felice solo con una soluzione del resto? –

+2

La dimensione è semplice, ma la posizione richiede un contesto. L'istanziazione dei modelli è un linguaggio funzionale, e il risultato dell'istanza può variare solo in base a ciò che si passa. Se si concatenano tali blocchi o si crea la memoria in un modello grande, è possibile farlo. Ad esempio, create una 'tupla' di array di sola lettura, ognuno con una posizione e dimensioni, partendo da un determinato punto e imballati. – Yakk

+0

Quindi forse avrei dovuto includerne il motivo. L'operatore [] sovraccarico nella classe ReadOnlyBlock chiama LoadFromROM (index + location); Lo strumento crea un file di sola lettura che ha ciascun blocco in ogni posizione specificata e che la classe sa caricare da quel punto. Non riesco a pensare a un modo per eliminare questa interdipendenza, ma ho il pieno controllo sullo strumento e sul codice di accesso, quindi cambiarlo non è fuori questione. –

risposta

1

io ancora non vedo la soluzione completa per la generazione del nome (che #location frammento), ma per il resto, penso che si potrebbe usare qualcosa di simile questo:

template< std::size_t Line > 
struct current_location : current_location< Line - 1 > {}; 

template<> 
struct current_location<0> : std::integral_constant< std::size_t, 0 > {}; 

#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int)) 

#define CreateReadOnlyBlock(name, ...)       \ 
template<>              \ 
const unsigned int ReadOnlyBlock<        \ 
    current_location<__LINE__-1>::value, NUMARGS(__VA_ARGS__) \ 
>::Data[]              \ 
    __asm__(".readonly__" #name)        \ 
    = { __VA_ARGS__ };           \ 
ReadOnlyBlock<current_location<__LINE__-1>::value,    \ 
       NUMARGS(__VA_ARGS__)> name;      \ 
template<>              \ 
struct current_location<__LINE__>        \ 
    : std::integral_constant<std::size_t,      \ 
     current_location<__LINE__-1>::value+NUMARGS(__VA_ARGS__)> \ 
{}; 
+0

Questo è perfetto! Grazie mille. In realtà non sono convinto di aver più bisogno del #location, dal momento che questo sembra mettere comunque i dati in un solido blocco sequenziale. Sono un po 'preoccupato che il compilatore possa riordinare le cose però, che è dove avrei bisogno dell'identificatore di posizione. In questo scenario, inserirò semplicemente la posizione come primo indice dell'array e otterrò lo strumento per rimuoverlo. Non carino, ma hey funziona! Ancora, grazie! –

0

Forse un po 'afferrare, ma sarebbe possibile con i modelli variadic invece di va_args? Qualcosa come

template <typename T1, ... TV> 
class ReadOnlyBlock 
{ 
    static unsigned int Data[sizeof(TV) + 1]; 
}; 

in pratica, ovunque tu abbia bisogno di "posizione", usa T1. Ovunque tu abbia bisogno di 'dimensione', usa sizeof (TV) + 1. Non hai un compilatore appropriato per verificarlo, ma forse è qualcosa da considerare ...

+0

Non sono proprio i dati che mi stanno uccidendo in questo momento, ma grazie per il suggerimento! Potrei convertirlo in modelli variadic in seguito, sono solo più a mio agio con il preprocessore C e sto solo cercando di farlo funzionare. –

0

Può essere d'aiuto. Ho scritto alcune cose per contare i blocchi possibile aggiungere DEF_BLOCK(size) prima della dichiarazione di blocco.Si può provare a riscrivere il mio esempio per allocare i dati dentro i miei blocchi

template<size_t ID> 
struct block_t 
{ 
    enum{location = 0}; 
}; 

#define LAST_BLOCK struct last_block_t{enum{id=__COUNTER__-1};}; 

#define SPEC2(ID, SIZE) template<> struct block_t<ID>{enum{location = block_t<ID-1>::location + SIZE, prev_block = ID-1, size = SIZE};} 
#define SPEC(ID, SIZE) SPEC2(ID, SIZE) 

#define DEF_BLOCK(SIZE) SPEC(__COUNTER__, SIZE) 

DEF_BLOCK(10); 
DEF_BLOCK(11); 
LAST_BLOCK; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    std::cout << block_t<last_block_t::id>::location << std::endl; 
    return 0; 
} 
0

Se vale quanto segue:

  • non si utilizza __COUNTER__ elswhere
  • Tutti gli array hanno lunghezza massima 5
  • Tutti gli array sono definiti nello stesso file di

Poi si può fare questo:

#include <iostream> 

#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N 
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1) 

template <int... Args> 
struct arg_counter { 
    enum { count = sizeof...(Args) }; 
}; 

#define INC_COUNTER1 arg_counter<-1>::count 
#define INC_COUNTER2 arg_counter<-1, __COUNTER__>::count 
#define INC_COUNTER3 arg_counter<-1, __COUNTER__, __COUNTER__>::count 
#define INC_COUNTER4 arg_counter<-1, __COUNTER__, __COUNTER__, __COUNTER__>::count 
#define INC_COUNTER5 arg_counter<-1, __COUNTER__, __COUNTER__, __COUNTER__, __COUNTER__>::count 

#define INC_COUNTER_IMPL2(count, ...) INC_COUNTER ## count 
#define INC_COUNTER_IMPL(count, ...) INC_COUNTER_IMPL2(count, __VA_ARGS__) 
#define INC_COUNTER(...) INC_COUNTER_IMPL(VA_NARGS(__VA_ARGS__), __VA_ARGS__) 

// removed: __asm__(".readonly__" #location "__" #name) 
#define CreateReadOnlyBlockImpl(name, location, size, ...)  \ 
    template<>             \ 
    const unsigned int ReadOnlyBlock<location, size>::Data[]  \ 
    = { __VA_ARGS__ };           \ 
    ReadOnlyBlock<location, size> name; 


#define CreateReadOnlyBlock(name, ...)         \ 
    CreateReadOnlyBlockImpl(name, __COUNTER__, INC_COUNTER(__VA_ARGS__), __VA_ARGS__); 

template<int Location, int Size> struct ReadOnlyBlock 
{ 
    static const unsigned int Data[Size]; 
    int loc() const { return Location; } 
    int size() const { return Size; } 
}; 

CreateReadOnlyBlock(readOnlyArray1, 0, 1, 2, 3); 
CreateReadOnlyBlock(readOnlyArray2, 4, 5, 6, 7); 
CreateReadOnlyBlock(readOnlyArray3, 9); 
CreateReadOnlyBlock(readOnlyArray4, 1, 2, 3, 4, 5); 

int main() 
{ 
    std::cout << "@" << readOnlyArray1.loc() << ": " << readOnlyArray1.size() << '\n'; 
    std::cout << "@" << readOnlyArray2.loc() << ": " << readOnlyArray2.size() << '\n'; 
    std::cout << "@" << readOnlyArray3.loc() << ": " << readOnlyArray3.size() << '\n'; 
    std::cout << "@" << readOnlyArray4.loc() << ": " << readOnlyArray4.size() << '\n'; 
} 

On ideone this prints:

@0: 4 
@4: 4 
@8: 1 
@9: 5 
+0

Sfortunatamente, gli array sono grandi quanto 1k, ma mi piace molto questa soluzione. Avrei dovuto chiarirlo, mi dispiace. Ho modificato il mio post. –

Problemi correlati