2009-11-23 2 views
3

Я использую поведение конструкторов глобальных переменных C++ для простого запуска кода при запуске. Это очень простая концепция, но немного трудно объяснить, так что позволь мне просто вставить код:C++ Препроцессор метапрограммирования: получение уникального значения?

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. */ 
    } 
}; 

Однако вручную инстанцировании что супер некрасивого класс каждый раз, когда один хочет зарегистрировать глобальные переменный Lua является громоздким; Именно поэтому я создал следующий макрос:

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

Так все, что вам нужно сделать, это положить, что в глобальном масштабе файла CPP и все работает отлично:

LUA_GLOBAL("LuaIsCool", true); 

Там вы идете! Теперь в Lua LuaIsCool будет переменная, инициализированная значением true!

Но вот проблема:

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

Который становится:

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

: (( мне нужно сцепить c_name макрос или он будет жаловаться на две переменные с одинаковым Я попытался заменить его __LINE__, но он фактически становится _____LuaGlobalAccess__LINE__ (т.е. он не заменяется).

Итак, есть способ каким-то образом получить уникальную строку или любое другое обходное решение?

PS: Да, я знаю имена, начинающиеся с _, зарезервированы; Я использую их в любом случае для таких целей, чтобы быть осторожным, чтобы выбрать имена, которые стандартная библиотека вряд ли когда-либо будет использовать. Кроме того, они находятся в пространстве имен.

+1

Примечание. Если идентификатор, начинающийся с подчеркивания, находится в пространстве имен, он зарезервирован только в том случае, если за ним следует заглавная буква. В противном случае вы можете использовать его. Поэтому измените биты «_Lua» на «_lua», и никто не может жаловаться. По крайней мере, о тех (имена, содержащие «_____», - это другая история). –

+1

не уверен, что я понял, почему вы не соглашаетесь с 'lua_name' вместо' c_name'? Разве это не так, чтобы быть уникальным? – int3

+1

в любом случае, я считаю, http://stackoverflow.com/questions/1489932/c-preprocessor-and-concatenation/1489985#1489985 решает вашу проблему «правильной подстановки». – int3

ответ

7

Вам нужно добавить дополнительный слой макросов, чтобы сделать препроцессор сделать правильную вещь:

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

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

Некоторых компиляторы также поддерживают __COUNTER__ макрос, который расширяется до нового, уникального целого числа каждый раз, когда она вычисляется , поэтому вы можете использовать это вместо __LINE__ для генерации уникальных идентификаторов. Я не уверен, что это действительно ISO C, хотя gcc принимает его использование с параметрами -ansi -pedantic.

+0

Спасибо, __COUNTER__ с двойным макросом кажется лучшим решением. Я googled и это не стандарт, но он поддерживается как gcc, так и компилятором microsoft, и это все, на что мое приложение совместимо. –

Смежные вопросы