ゲームBitfighterの Lua インターフェイスを実装しながら、繰り返しとコードの重複を減らすために x-macros を使用しています。次のコードは正常に動作します。
// Fn name Valid param profiles Profile count
# define TELEPORTER_LUA_METHOD_TABLE \
TELEPORTER_LUA_METHOD_ITEM(addDest, ARRAYDEF({{ PT, END }}), 1 ) \
TELEPORTER_LUA_METHOD_ITEM(delDest, ARRAYDEF({{ INT, END }}), 1 ) \
TELEPORTER_LUA_METHOD_ITEM(clearDests, ARRAYDEF({{ END }}), 1 ) \
// BLOCK A Start
const luaL_reg Teleporter::luaMethods[] =
{
# define TELEPORTER_LUA_METHOD_ITEM(name, b, c) { #name, luaW_doMethod<Teleporter, &Teleporter::name > },
TELEPORTER_LUA_METHOD_TABLE
# undef TELEPORTER_LUA_METHOD_ITEM
{ NULL, NULL }
};
// BLOCK A End
/* Generates the following:
const luaL_reg Teleporter::luaMethods[] =
{
{ "addDest", luaW_doMethod<Teleporter, &Teleporter::addDest > }
{ "delDest", luaW_doMethod<Teleporter, &Teleporter::delDest > }
{ "clearDests", luaW_doMethod<Teleporter, &Teleporter::clearDests > }
{ NULL, NULL }
};
*/
// BLOCK B Start
const LuaFunctionProfile Teleporter::functionArgs[] =
{
# define TELEPORTER_LUA_METHOD_ITEM(name, profiles, profileCount) { #name, profiles, profileCount },
TELEPORTER_LUA_METHOD_TABLE
# undef TELEPORTER_LUA_METHOD_ITEM
{ NULL, { }, 0 }
};
// BLOCK B End
/* Generates the following:
const LuaFunctionProfile Teleporter::functionArgs[] =
{
{ "addDest", {{ PT, END }}, 1 }
{ "delDest", {{ INT, END }}, 1 }
{ "clearDests", {{ END }}, 1 }
{ NULL, { }, 0 }
};
*/
#undef TELEPORTER_LUA_METHOD_TABLE
ここまでは順調ですね。
私が何十ものクラスで本質的に同じことをすることを除いて。私が本当にやりたいことは、各クラスでメソッドテーブルを定義し(これは何でも呼び出すことができます)、次に次のように呼び出すことができる2つのマクロを定義することです:
GENERATE_LUA_METHODS(Teleporter, TELEPORTER_LUA_METHOD_TABLE)
GENERATE_FUNCTION_PROFILE(Teleporter, TELEPORTER_LUA_METHOD_TABLE)
上記のブロック A と B で繰り返されるコードをすべて回避するためです。明らかな方法は、ネストされたマクロを使用することですが、残念ながら、これは違法です。
より良い方法はありますか?
解決
この質問を投稿したとき、答えは「できない」と確信していました。代わりに、2 つのアプローチがありましたが、そのうちの 1 つはまさに私が探していたものでした。また、マクロの落とし穴 (多数あります) についても良い議論があり、いくつかの代替アプローチが提案されました。受け入れられた回答に基づいて私が開発した実装は、クリーンで理解しやすく、汚れたマクロが見えない便利な場所にあります。
どこかの隠れ家で:
#define ARRAYDEF(...) __VA_ARGS__ // Don't confuse the preprocessor with array defs
////////////////////////////////////////
////////////////////////////////////////
//
// Some ugly macro defs that will make our Lua classes sleek and beautiful
//
////////////////////////////////////////
////////////////////////////////////////
//
// See discussion of this code here:
// http://stackoverflow.com/questions/11413663/reducing-code-repetition-in-c
//
// Start with a definition like the following:
// #define LUA_METHODS(CLASS, METHOD) \
// METHOD(CLASS, addDest, ARRAYDEF({{ PT, END }}), 1 ) \
// METHOD(CLASS, delDest, ARRAYDEF({{ INT, END }}), 1 ) \
// METHOD(CLASS, clearDests, ARRAYDEF({{ END }}), 1 ) \
//
#define LUA_METHOD_ITEM(class_, name, b, c) \
{ #name, luaW_doMethod<class_, &class_::name > },
#define GENERATE_LUA_METHODS_TABLE(class_, table_) \
const luaL_reg class_::luaMethods[] = \
{ \
table_(class_, LUA_METHOD_ITEM) \
{ NULL, NULL } \
}
// Generates something like the following:
// const luaL_reg Teleporter::luaMethods[] =
// {
// { "addDest", luaW_doMethod<Teleporter, &Teleporter::addDest > }
// { "delDest", luaW_doMethod<Teleporter, &Teleporter::delDest > }
// { "clearDests", luaW_doMethod<Teleporter, &Teleporter::clearDests > }
// { NULL, NULL }
// };
////////////////////////////////////////
#define LUA_FUNARGS_ITEM(class_, name, profiles, profileCount) \
{ #name, profiles, profileCount },
#define GENERATE_LUA_FUNARGS_TABLE(class_, table_) \
const LuaFunctionProfile class_::functionArgs[] = \
{ \
table_(class_, LUA_FUNARGS_ITEM) \
{ NULL, { }, 0 } \
}
// Generates something like the following:
// const LuaFunctionProfile Teleporter::functionArgs[] =
// {
// { "addDest", {{ PT, END }}, 1 }
// { "delDest", {{ INT, END }}, 1 }
// { "clearDests", {{ END }}, 1 }
// { NULL, { }, 0 }
// };
////////////////////////////////////////
////////////////////////////////////////
各クラス ファイルで:
// Fn name Param profiles Profile count
#define LUA_METHODS(CLASS, METHOD) \
METHOD(CLASS, addDest, ARRAYDEF({{ PT, END }}), 1 ) \
METHOD(CLASS, delDest, ARRAYDEF({{ INT, END }}), 1 ) \
METHOD(CLASS, clearDests, ARRAYDEF({{ END }}), 1 ) \
GENERATE_LUA_METHODS_TABLE(Teleporter, LUA_METHODS);
GENERATE_LUA_FUNARGS_TABLE(Teleporter, LUA_METHODS);
#undef LUA_METHODS