Reputation: 15333
I'm trying to set up some stuff with Lua, but the specifics of Lua aren't important for my question.
What I would like to be able to do is call a function, say OpenLib<T>(L)
, and have it get the table name for a particular class (as well as it's table) and register it with Lua. It essentially boils down to this:
template <class T>
static void OpenLib(lua_State* L)
{
// this func does some other stuff too that I'm omitting, important bit below
if (T::myTable && T::myTableName)
{
luaL_openlib(L, T::myTableName, T::myTable, 0);
}
}
I've tried this a few different ways and I can't get it to work right. I tried making a base class that contains myTable and myTableName like so:
class LuaInfo
{
public:
static const char* myTableName;
static luaL_reg* myTable;
}
Then I could just inherit from LuaInfo, and then fill in the info that I needed. That didn't work because all classes that inherit from LuaInfo would get the same info, so I looked around and got the idea of doing this:
template <class t>
class LuaInfo
// ...
Which made the syntax to initialize it a little silly as I now have to do class Widget : public LuaInfo, but it was closer to working.
template <class T>
void OpenLib(lua_State* L)
{
if (T::myTable && T::myTableName)
{
luaL_openlib(L, LuaInfo<T>::myTableName, LuaInfo<T>::myTable, 0);
}
}
I've tried a few variants of this to try to get it right but I keep getting errors like
undefined reference to `ag::LuaInfo<ag::ui::Widget>::myTable'
Is what I want to do possible, and if so, whats the right way to go about doing it?
Upvotes: 0
Views: 229
Reputation: 73520
Using
template<typename T>
class LuaInfo
{
static const char* myTableName;
static lua_reg* myTable;
};
should work OK.
Your problem is that you need to define your static variables.
A single source file containing a bunch of lines like this will solve it
luaL_reg* LuaInfo<ag::ui::Widget>::myTable = 0;
const char * LuaInfo<ag::ui::Widget>::myTableName = 0;
luaL_reg* LuaInfo<ag::ui::OtherClass>::myTable = 0;
const char * LuaInfo<ag::ui::OtherClass>::myTableName = 0;
and so on.
You may want to define a macro to make this nicer.
#define LUAINFOIMPL(X) luaL_reg* LuaInfo<X>::myTable=0; const char * LuaInfo<X>::myTableName=0
LUAINFOIMPL( ag::ui::Widget );
LUAINFOIMPL( ag::ui::OtherClass );
However its a bit ugly to scale that way. I was thinking traits style templates might solve this .. but I'm not sure they scale any better.
Upvotes: 1
Reputation: 18326
Your first attempt works fine for me. I guess you just forgot to initialize the static members and got some link errors about that. This is what I did:
template <class T>
static void OpenLib(lua_State* L)
{
// this func does some other stuff too that I'm omitting, important bit below
if (T::myTable && T::myTableName)
{
luaL_openlib(L, T::myTableName, T::myTable, 0);
}
}
class LuaInfo
{
public:
static const char* myTableName;
static luaL_reg* myTable;
};
//init static members
const char* LuaInfo::myTableName = 0;
luaL_reg* LuaInfo::myTable = 0;
int main()
{
OpenLib<LuaInfo>(0);
}
Now if you want to give other info to OpenLib
you have to create a new class like LuaInfo
and give that new class as template parameters.
But why do you want this info as a template parameters? IMO, this is much simpler:
struct LuaInfo
{
const char* myTableName;
luaL_reg* myTable;
};
static void OpenLib(lua_State* L, LuaInfo info)
{
// this func does some other stuff too that I'm omitting, important bit below
if (info.myTable && info.myTableName)
{
luaL_openlib(L, info.myTableName, info.myTable, 0);
}
}
int main()
{
LuaInfo info = {/*some values here*/};
OpenLib(0, info);
}
Upvotes: 0