代码之家  ›  专栏  ›  技术社区  ›  Stelios Papamichail

基于C++的DSL,支持使用带参数列表的运算符[]

  •  0
  • Stelios Papamichail  · 技术社区  · 2 年前

    我需要用C++编写一个自定义DSL,用于定义Pokmon、能力、向特定Pokmon教授能力,然后模拟决斗。到目前为止,我已经设法使DSL的大部分工作如前所述,但我很难实现以下代码:

    DEAR "Pikachu" LEARN [
        ABILITY_NAME(Electric_Shock)
        ABILITY_NAME(Lightning_Rod)
    ]
    

    这个DSL代码基本上应该转换成有效的C++代码,将指定的能力传授给DEAR宏之后指定的Pokmon。到目前为止,我为这一特定部分所做的工作如下:

    /**
     * \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)
    

    这个 getPokemonByName() 返回一个 Pokemon* 如果存在具有给定名称的Pokmon(在DEAR宏之后),或者 nullptr 否则(我将发出错误并在访问之前终止 nullptr 稍后)。同样的逻辑也适用于 getAbilityByName() 函数,该函数反过来返回 SingleAbilityExpr* .

    我的思考过程是想办法将各种 SingleAbilityExpr* s在 [] 变成一个,然后使过载 operator[] 以便将能力传授给所选的Pokmon。问题是,我无法找到用这种特定语法破解此功能的方法。有没有一种替代我的方法可以实现我想要的?

    起初,我希望如果 ABILITY_NAME 宏将发出 , 最后,我可以超载 operator, 在中 SingleAbilityExpr 类,从而以这种方式收集它们。遗憾的是,由于最后一个尾随逗号,这似乎不起作用,我发现使用c++11无法使用它。

    2 回复  |  直到 2 年前
        1
  •  2
  •   user7860670    2 年前

    更简单的方法是 getAbilityByName 返回带有重载的集合 operator () (Collection &) -> Collection & 并将宏定义为

    #define ABILITY_NAME(mp_name) (getAbilityByName(#mp_name))

    因此,列表将扩展到以下内容

    [
        (getAbilityByName("Electric_Shock")) // () are normal parentheses
        (getAbilityByName("Lightning_Rod")) // () are overloaded operator
    ]
    

    这不仅需要一个重载运算符,而且还可以获得正确的求值顺序。

        2
  •  1
  •   HolyBlackCat    2 年前

    C++23添加多参数 operator[] ,但在您的情况下这是无用的,因为您最终会得到以下结果:(在添加逗号后 ABILITY_NAME )

    foo[
        getAbilityByName("a"),
        getAbilityByName("b"),
        getAbilityByName("c"), // <--
    ]
    

    这没有用,因为后面的逗号是一个错误。

    相反,你应该这样做 #define ABILITY_NAME(name) +getAbilityByName(#name) 哪里 getAbilityByName() 返回一个能力列表(包装 std::vector 可能),具有过载运算符:

    • Unary + ,返回的列表保持不变,以及
    • 二进制的 + ,用于连接列表。

    然后 操作员[] 应接受列表作为唯一参数:

    foo[
        +getAbilityByName("a") // Unary +
        + getAbilityByName("b") // Binary +
        + getAbilityByName("c") // Binary +
    ]