views:

322

answers:

1

Hi, I'm exploiting the behavior of the constructors of C++ global variables to run code at startup in a simple manner. It's a very easy concept but a little difficult to explain so let me just paste the code:

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

However manually instantiating that super ugly class every time one wants to register a Lua global variable is cumbersome; that's why I created the following macro:

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

So all you have to do is put that in the global scope of a cpp file and everything works perfectly:

LUA_GLOBAL("LuaIsCool", true);

There you go! Now in Lua LuaIsCool will be a variable initialized to true!

But, here is the problem:

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

Which becomes:

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

:(( I need to concatenate c_name in the macro or it will complain about two variables with the same name; I tried replacing it with __LINE__ but it actually becomes _____LuaGlobalAccess__LINE__ (ie it doesn't get replaced).

So, is there a way to somehow obtain an unique string, or any other workaround?

Thanks!

PS: yes I know names that begin with _ are reserved; I use them anyway for purposes like this being careful to pick names that the standard library is extremely unlikely to ever use. Additionally they are in a namespace.

+7  A: 

You need to add an extra layer of macros to make the preprocessor do the right thing:

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

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

Some compilers also support the __COUNTER__ macro, which expands to a new, unique integer every time it is evaluated, so you can use that in place of __LINE__ to generate unique identifiers. I'm not sure if it's valid ISO C, although gcc accepts its use with the -ansi -pedantic options.

Adam Rosenfield
Thanks, __COUNTER__ with the double macro thingy seems to be the best solution. I googled and it's not standard, but it's supported by both gcc and the microsoft's compiler, and that's all my application is compatible with.
Andreas Bonini