我需要用 C++ 编写一个自定义 DSL,用于定义 Pokémon、能力、向特定 Pokémon 教授能力,然后模拟决斗。到目前为止,我已经成功地使大部分 DSL 按照描述的方式工作,但我很难实现以下代码:
DEAR "Pikachu" LEARN [
ABILITY_NAME(Electric_Shock)
ABILITY_NAME(Lightning_Rod)
]
此 DSL 代码基本上应该转换为有效的 C++ 代码,该代码向 DEAR 宏之后指定的 Pokémon 传授指定的能力。到目前为止,我为此特定部分所做的工作如下:
/**
* \brief
*/
#define DEAR ; (*getPokemonByName(
/**
* \brief
*/
#define LEARN ))
/**
* \brief Retrieves the ability with the given name, if it exists.
* Otherwise, nullptr is returned.
* \param name The name of the ability to look for.
*/
#define ABILITY_NAME(name) getAbilityByName(#name)
如果存在给定名称(在 DEAR 宏之后)的 Pokémon,则
getPokemonByName()
返回 Pokemon*
,否则返回 nullptr
(我将在稍后访问 nullptr
之前发出错误并终止)。同样的逻辑适用于 getAbilityByName()
函数,该函数又返回 SingleAbilityExpr*
。
我的思考过程是想出一种方法,将
SingleAbilityExpr*
中的各种[]
组合成一个,然后在神奇宝贝类中重载operator[]
,以便向所选神奇宝贝传授能力。问题是我无法找到一种方法来使用这种特定的语法来破解此功能。除了我的方法之外,还有其他方法可以实现我想要的吗?
最初,我希望如果
ABILITY_NAME
宏最后发出 ,
,我可以重载 operator,
类中的 SingleAbilityExpr
,从而以这种方式收集它们。遗憾的是,由于最后一个尾随逗号,这似乎不起作用,我发现无法使用 c++11 来使用它。
C++23 添加了多参数
operator[]
,但在你的情况下没有用,因为你最终会得到以下结果:(在 ABILITY_NAME
添加逗号后)
foo[
getAbilityByName("a"),
getAbilityByName("b"),
getAbilityByName("c"),
]
这没有用,因为结尾的逗号是错误的。
相反,你应该这样做
#define ABILITY_NAME(name) +getAbilityByName(#name)
,其中 getAbilityByName()
返回一个能力列表(可能是 std::vector
的包装),并带有重载的运算符:
+
,返回列表不变,并且+
,连接列表。然后
operator[]
应该接受列表作为唯一的参数:
foo[
+getAbilityByName("a") // Unary +
+ getAbilityByName("b") // Binary +
+ getAbilityByName("c") // Binary +
]