在编译时动态创建映射

时间:2015-03-12 04:54:59

标签: c++ template-meta-programming compile-time

我在游戏引擎中实现了Lua。导出到Lua的所有函数都有以luavoidluaintluabool开头的标题,只是为了快速参考预期的参数,所以我可以一眼看出这个函数正在出口。

#define luavoid(...) void

luavoid(std::string s) TextMsg()
{
    std::string s;
    ExtractLuaParams(1, s);
    ::TextMsg(s.c_str());
}

要将函数实际导出到Lua,它们会被添加到字典中。启动时,地图用于调用lua_register

std::unordered_map<std::string, ScriptCall> _callMap = {
    { "TextMsg", TextMsg },
    ...
}

会导出很多功能。我不想手动维护这个地图,而是想自动创建它。

我的第一直觉是在编译时使用宏。我最初放弃它并开始编写一个程序来解析代码(作为预构建事件),因为所有函数都可以与luaX宏进行文本匹配。它会创建一个自动生成地图的头文件。

然后我在找到一种方法后,在编译时再回去做。在我最终在游戏中实现它之前,我想出了这个解决方案作为一个例子:

using MapType = std::unordered_map<std::string, int>;

template <MapType& m>
struct MapMaker
{
    static int MakePair(std::string s, int n)
    {
        m[s] = n;
        return n;
    }
};

#define StartMap(map) MapType map
#define AddMapItem(map, s, n) int map##s = MapMaker<map>::MakePair(#s, n)

StartMap(myMap);
AddMapItem(myMap, abc, 1);
AddMapItem(myMap, def, 2);
AddMapItem(myMap, ghi, 3);

void main()
{
    for (auto& x : myMap)
    {
        std::cout << x.first.c_str() << "->" << x.second << std::endl;
    }
}

有效。

我的问题是,这有多可怕并且可以改进吗?我想要的最后一个是将字符串映射到函数的列表。有没有更好的方法来创建地图,还是应该使用文本解析方法?

要温柔(-ish)。这是我第一次使用这样的模板进行编码。我认为这属于模板元编程。

1 个答案:

答案 0 :(得分:2)

  

这有多可怕,可以改进吗?

介于丑陋和可怕之间。 (有些问题最好没有问题。)是的......

  

我想要的最后一个是将字符串映射到函数的列表。有没有更好的方法来创建地图,还是应该使用文本解析方法?

最简单的事情是:

#define ADDFN(FN) { #FN, FN }

std::unordered_map<std::string, ScriptCall> _callMap = {
    ADDFN(TextMsg),
    ...
};

这使用宏来自动化字符串文字函数名称和标识符中的重复 - 您的实现没有进一步的实质性添加。

那就是说,你可以尝试自动化比你的实现更进一步的东西,可能是这样的:

#define LUAVOID(FN, ...) \
    void FN(); \
    static auto addFN ## __LINE__ = myMap.emplace(#FN, FN); \
    void FN()

LUAVOID(TextMsg, string s)
{
    ...
}

看到它正在运行here

这里的想法是宏生成一个函数声明,以便它可以注册函数,然后是一个定义。 __LINE__可能足以满足标识符的唯一性 - 假设您有一个文件执行此操作,并且您的编译器替换了数字文字(我使用过的所有编译器都这样做,但我无法记住标准要求)。 emplace函数具有非void返回类型,因此可以直接用于插入map

  

要温柔(-ish)。这是我第一次使用这样的模板进行编码。

对不起。

  

我认为这属于模板元编程。

这是有争议的。许多C ++程序员(包括我自己)都会想到&#34;元编程&#34;涉及更高级的模板使用 - 例如可变长度的参数列表,递归实例化和专业化 - 但许多其他人认为所有模板使用都是&#34;元编程&#34;因为模板提供了如何创建实例化的说明,这在技术上足以构成metaprogramming