3 Stimmen

C++ Präprozessor-Metaprogrammierung: Erlangung eines eindeutigen Wertes?

Ich nutze das Verhalten der Konstruktoren globaler C++-Variablen, um auf einfache Weise Code beim Start auszuführen. Es ist ein sehr einfaches Konzept, aber ein wenig schwierig zu erklären, so lassen Sie mich nur den Code einfügen:

struct _LuaVariableRegistration
{
    template<class T>
    _LuaVariableRegistration(const char* lua_name, const T& c_name) {
        /* ... This code will be ran at startup; it temporarily saves lua_name and c_name in a std::map and when Lua is loaded it will register all temporarily global variables in Lua. */
    }
};

Allerdings ist es mühsam, diese superhässliche Klasse jedes Mal manuell zu instanziieren, wenn man eine globale Lua-Variable registrieren will; deshalb habe ich das folgende Makro erstellt:

#define LUA_GLOBAL(lua_name, c_name) static Snow::_LuaVariableRegistration _____LuaGlobal ## c_name (lua_name, c_name);

Sie müssen das also nur in den globalen Bereich einer cpp-Datei setzen, und alles funktioniert perfekt:

LUA_GLOBAL("LuaIsCool", true);

Na also! Jetzt in Lua LuaIsCool wird eine Variable sein, die mit true initialisiert wird!

Aber hier liegt das Problem:

LUA_GLOBAL("ACCESS_NONE", Access::None);

Das wird:

static Snow::_LuaVariableRegistration _____LuaGlobalAccess::None ("ACCESS_NONE", &Access::None);

:(( Ich muss verketten c_name im Makro, sonst beschwert es sich über zwei Variablen mit demselben Namen; ich habe versucht, sie zu ersetzen durch __LINE__ aber es wird tatsächlich _____LuaGlobalAccess__LINE__ (d.h. er wird nicht ersetzt).

Gibt es also eine Möglichkeit, eine eindeutige Zeichenfolge zu erhalten, oder eine andere Abhilfe?

PS: Ja, ich weiß, dass Namen, die mit _ beginnen, reserviert sind; ich verwende sie trotzdem für Zwecke wie diesen, wobei ich darauf achte, Namen zu wählen, die die Standardbibliothek höchstwahrscheinlich nie verwenden wird. Außerdem befinden sie sich in einem Namensraum.

7voto

Adam Rosenfield Punkte 373807

Sie müssen eine zusätzliche Schicht von Makros hinzufügen, damit der Präprozessor das Richtige tut:

#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)

#define LUA_GLOBAL(lua_name, c_name) ... TOKENPASTE2(_luaGlobal, __LINE__) ...

Einige Compiler unterstützen auch die __COUNTER__ Makro, das sich bei jeder Auswertung zu einer neuen, eindeutigen Ganzzahl erweitert, so dass Sie es anstelle von __LINE__ um eindeutige Identifikatoren zu erzeugen. Ich bin mir nicht sicher, ob es in ISO C gültig ist, obwohl gcc seine Verwendung mit dem -ansi -pedantic Optionen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X