代码之家  ›  专栏  ›  技术社区  ›  Questor

宏生成链式else if

  •  1
  • Questor  · 技术社区  · 5 月前

    使用X宏,使用模块外提供的列表使几个不同的东西保持同步。

    其中一部分涉及创建else/if链来验证字符串。

    我目前正在做这件事:

    if (0) {
       // this will never run, and be compiled out
    }
    #define X(name) else if (some_thing == #name) { // do thing based on name... }
       MY_LIST
    #undef X
    else {
       // Report unrecognized string...
    }
    

    但我觉得它有点难看(我不是不可执行文件的忠实粉丝 if(0) {} ).

    我曾考虑过使用 switch 声明。。。

    constexpr hash(const char* const str, size_t len, uint64_t init_value)
       // implementation left to imagination of the reader)...
    
    //...
    
    switch(hash(some_thing, len(some_thing))) {
    #define X(name) case hash(#name, const_len(#name)): { break; }
       MY_LIST
    #undef X
       default: 
       {
          good_thing = false;
          break;
       }
    }
    // Now that it has been validated as a good string... save it etc.
    

    但我担心碰撞(就像碰撞一样不太可能)。

    有没有一种方法可以在不以a开头的情况下执行if/else链 if(0) ?

    我被困住了 std::14 如果它有帮助(我知道它没有)。

    2 回复  |  直到 5 月前
        1
  •  1
  •   Eugene    5 月前

    你可以在每个字符串匹配中设置一个标志,这样你就不需要 else :

    bool found = false;
    #define X(name) if (some_thing == #name) { found = true; /* do thing based on name here ...*/ }
       MY_LIST
    #undef X
    if (!found) {
       // Report unrecognized string...
    }
    

    或者,如果在匹配字符串后避免比较很重要,你可以这样做(但在我看来,这更难理解):

    #define X(name) if (some_thing == #name) { /* do thing based on name... */ } else 
       MY_LIST
    #undef X
    {
       // Report unrecognized string...
    }
    
        2
  •  1
  •   GandhiGandhi    5 月前

    有没有一种方法可以在不以if(0)开头的情况下执行if/else链?

    我不知道用宏生成if-else链的更好方法。我同意它看起来确实有点古怪。

    但是,这里有另一种方法来验证此字符串是否是从为C++14编译的X-Macros构建的集合中的一个字符串。这取决于你的口味,如果你认为这对你的代码库更好或不好。

    #include <set>
    #include <string>
    
    void validate_string(std::string some_thing) {
        /* Build the set of strings to test against with X-Macros */
        static const std::set<std::string> validate_set = {
        #define X(name) #name,
        MY_LIST
        #undef X
        };
    
        if (validate_set.find(some_thing) != validate_set.end()){
            /* Then some_thing is one of the compile time constants */
        }
        
    }