【问题标题】:avoiding impossible cases in macro避免宏中不可能的情况
【发布时间】:2022-01-17 03:17:22
【问题描述】:

考虑以下宏:

#define checkExists(map, it, value) {\
    it = map.find(value);\
    if(it == map.end()){\
        if(!strcmp(typeid(value).name(), "Ss")){ /* value is an std::string */\
            manageError(ERR_CANT_FIND_RESSOURCES, "in %s __ failed to find %s in map %s", __FUNCTION__, value.c_str(), #map);\
        \
        }else if(!(strcmp(typeid(value).name(), "Pc") * strcmp(typeid(value).name(), "PKc"))){ /* value is either char* or const char* */\
            manageError(ERR_CANT_FIND_RESSOURCES, "in %s __ failed to find %s in map %s", __FUNCTION__, value #map); /* problem here because for gcc value could be an std::string */ \
        \
        } else \
            manageError(ERR_CANT_FIND_RESSOURCES, "in %s __ failed to find 0x%04X in map %s", __FUNCTION__, value #map); /* problem here because for gcc value could be an std::string */\
    }\
}

manageError 也是一个调用函数logWarning 的宏,它只接受基本类型(例如intchar* ...)。原型是:

#define manageError(error_code, error_str, ...) {\
    {\
        logWarning(error_str, ##__VA_ARGS__);\
        return error_code;\
    }\
}

int logWarning(const char* printf_format, ...);

所以如果我的valuestd::string,我将给manageError 一个const char *

似乎 checkExists 没有评估编译时间...所以 gcc 非常聪明,它不允许我最后两个 manageError 调用,因为它将 value 视为 std::string 或这是不可能的,因为std::string 只有在第一种情况下才有可能。

例如,这不起作用:

std::string foo;
checkExists(myMap, myMapIterator, foo);

gcc 输出:

error: cannot pass objects of non-trivially-copyable type 'const string {aka const struct std::basic_string<char>}' through '...'

你知道我该如何解决这个问题吗?

编辑

该机制的想法是在发生错误时能够离开当前功能。例如:

int func(){
    std::string foo;
    checkExists(myMap, myMapIterator, foo); //leaves the function if foo is not found inside myMap
    return 0;
}

所以我必须使用宏才能离开该功能(我无法使用模板)。

【问题讨论】:

  • @Jarod42 我正在使用 C++(不要介意类似 C 的指令)。
  • @Jarod42 更新了它,但认为它会提供相同的解决方案,因为 C 方法在 C++ 中有效。
  • 模板怎么样?
  • 好的,我知道你在做什么。你想给出不同的消息,取决于value的类型;这听起来像是一个重载的函数。
  • 为什么要使用宏?考虑@Jarod42 建议的函数模板。如果需要,可以向其中添加一个宏来获取封闭的函数名称。但按照惯例,宏应该是ALL_CAPS_SNAKE_CASE

标签: c++ string macros


【解决方案1】:

无论输入类型如何,我都通过将value 转换为std::string 解决了这个问题。

#define checkExists(map, it, value) {\
    it = map.find(value);\
    if(it == map.end()){\
        std::stringstream tmpSs;\
        if(!(strcmp(typeid(value).name(), "Pc") * strcmp(typeid(value).name(), "PKc") * strcmp(typeid(value).name(), "Ss"))){\
            tmpSs << value;\
        }else{\
            tmpSs << "0x" << std::uppercase << std::setfill('0') << std::setw(4) << std::hex << value; /* converting value to hex format */\
        }\
        \
        manageError(ERRCAN_T_FIND_RESSOURCES, "in %s __ failed to find %s in map %s", __FUNCTION__, tmpSs.str().c_str(), #map);\
    }\
}

【讨论】:

  • 正如我们所说,重载/模板可能会简化代码:template &lt;typename T&gt;std::string to_string(const T&amp; t) { if constexpr (std::is_same_v&lt;const char*, T&gt; || std::is_same_v&lt;std::string, T&gt;) return p; else { std::stringstream ss; ss &lt;&lt; "0x" &lt;&lt; std::uppercase &lt;&lt; std::setfill('0') &lt;&lt; std::setw(4) &lt;&lt; std::hex &lt;&lt; t; return ss.str(); }} 然后你的 MACRO 就是 #define checkExists(map, it, value) { it = map.find(value); if(it == map.end()){ manageError(ERRCAN_T_FIND_RESSOURCES, "in %s __ failed to find %s in map %s", __FUNCTION__, to_string(value).c_str(), #map);
  • @Jarod42 感谢std::is_same 的技巧,我将使用它来代替typeid。但是以我的拙见,您只是将我的“宏”拆分为“宏+模板函数”。顺便说一句,to_string,我不认为p 对应任何东西(return p)。不过还是谢谢。
  • 错字:return t;。确实想法是拆分宏。将 MACRO 限制在只能在 MACRO 中执行的部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-05
  • 1970-01-01
相关资源
最近更新 更多