2013-03-21 3 views
5

Ich habe eine Klasse erstellt, die wie ein Array aussieht, aber anstatt die Daten im Programm selbst zu speichern, streamt sie das Byte aus einer Datei (um den RAM-Einfluss zu reduzieren). Jetzt habe ich all diese Arbeit bekam, aber der Programmierer muss die Klasse definieren mit dem folgenden:Erstellen von Template-Parametern zum Zeitpunkt des Kompilierens

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

Beispiel:

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

Beachten Sie, dass dies für einen Embedded-Prozessor ist, und die asm-Richtlinie durchläuft ein Tool im Assembler, um die schreibgeschützte Datei zu erstellen.

Also hier ist meine Frage: Wie kann ich die Variablen "Standort" und "Größe" beseitigen? Ich hasse es, dass der Programmierer diese manuell eintippen muss, und würde es viel lieber bevorzugen, diese zur Kompilierzeit zu erzeugen. Anstatt also den Programmierer zu geben brauchen:

//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); 

Sie konnten nur geben:

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

und die entsprechenden Konstanten erzeugt werden würde. Im Grunde suche ich nach einer Möglichkeit, diese Konstanten auf der Basis früherer Definitionen zur Kompilierzeit zu erzeugen und zu platzieren. C++ 11 ist ein faires Spiel, ich kenne es nicht besonders gut (etwas mit conetexpr scheint plausibel?). Auch C-Preprocessor ist in Ordnung, wenn es es nicht hässlicher macht, als es bereits ist. Ist das möglich?

EDIT für Klarheit:

In der ReadOnlyBlock Klasse gibt es diese Methode:

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

Es ist eine intrinsische gegenseitige Abhängigkeit zwischen dem Ort Größe und der ROM-Datei, die ich nicht denken kann, wie zu brechen. I tun haben vollständige Kontrolle über die Werkzeugkette aber auch, aber ich brauche eine Möglichkeit, das Assembler-Tool zu übergeben, wie die Datei zu konstruieren sowie auf den C++ Code anzuzeigen, wo die Blöcke in der Datei liegen.

Ein weiterer EDIT:

Die Datei und die Blöcke können sein ganz groß, so viel wie 1k Worte, so viele Präprozessor Magie könnte, dass Zusammenbruch gegeben. Danke auch allen für die bisherige Hilfe!

+0

Die '# location' im '__asm__' Teil bringt es wirklich um. Brauchst du das wirklich oder würdest du nur mit einer Lösung des Rests zufrieden sein? –

+2

Die Größe ist einfach, aber die Position würde Kontext erfordern. Die Template-Instanziierung ist eine funktionale Sprache, und das Ergebnis der Instanziierung kann nur davon abhängen, was Sie übergeben. Wenn Sie solche Blöcke verketten oder den Speicher in einer großen Vorlage erstellen, kann dies geschehen. Dh, erstellen Sie ein "Tupel" von Nur-Lese-Arrays, jedes mit einem Ort und einer Größe, beginnend an einer bestimmten Stelle, und gepackt. – Yakk

+0

Also vielleicht hätte ich den Grund dafür angeben sollen. Der überladene [] -Operator in der ReadOnlyBlock-Klasse ruft LoadFromROM auf (index + location); Das Tool erstellt eine schreibgeschützte Datei, die jeden Block an jedem angegebenen Speicherort enthält, und die Klasse kann von diesem Punkt aus laden. Ich kann mir keinen Weg vorstellen, diese gegenseitige Abhängigkeit zu beseitigen, aber ich habe die volle Kontrolle über das Tool und den Zugriffscode, so dass es nicht unmöglich ist, sie zu ändern. –

Antwort

1

ich nicht immer noch zur Erzeugung des Namens die vollständige Lösung sehen (das #location-Fragment), aber für den Rest, ich denke, Sie so etwas wie verwenden könnte dies:

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

Das ist perfekt! Ich danke dir sehr. Ich bin eigentlich nicht überzeugt, dass ich das #Location mehr brauche, da dies die Daten ohnehin in einen soliden sequentiellen Block zu bringen scheint. Ich bin ein wenig besorgt, dass der Compiler Dinge neu ordnen könnte, wo ich die Ortskennung benötige. In diesem Szenario würde ich einfach den Speicherort als ersten Index in das Array einfügen und das Tool dazu bringen, es zu entfernen. Nicht schön, aber hey es funktioniert! Nochmals vielen Dank! –

0

Vielleicht ein bisschen greifen, aber wäre es mit variadischen Vorlagen statt va_args möglich? So etwas wie

im Grunde, überall wo Sie 'Standort' benötigen, verwenden Sie T1. Überall dort, wo Sie 'Größe' benötigen, verwenden Sie sizeof (TV) + 1. Haben Sie keinen geeigneten Compiler, um dies zu testen, aber vielleicht ist es etwas zu überlegen ...

+0

Es sind nicht wirklich die Daten, die mich jetzt töten, aber danke für den Vorschlag! Ich kann es später in variadische Vorlagen umwandeln, ich bin einfach wohler mit dem C-Präprozessor und versuche nur, es zum Laufen zu bringen. –

0

Es kann helfen. Ich habe ein paar Sachen geschrieben, Blöcke zu zählen kann DEF_BLOCK(size) vor Block Deklaration hinzufügen.Sie können versuchen, mein Beispiel umschreiben Daten in meinem Blöcke zuzuteilen

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

Wenn folgendes gilt:

  • nicht benötigt __COUNTER__ elswhere
  • Alle Arrays haben maximale Länge 5
  • Alle Arrays in der gleichen Datei

Dann können Sie diese definiert sind, tun:

#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

Leider sind die Arrays so groß wie 1k Wörter, aber ich mag diese Lösung wirklich. Ich hätte das klären sollen, Entschuldigung. Ich habe meinen Beitrag bearbeitet. –

Verwandte Themen