【问题标题】:Specializing macro with arguments使用参数专门化宏
【发布时间】:2020-04-09 05:20:09
【问题描述】:

假设我有以下宏:

#define LOG(L, ...) func(L, __VA_ARGS__);

其中 L 可以是 INFO, WARN, FATAL 之一

现在我想以不同的方式为FATAL 定义它。

#define LOG(FATAL, ...) {func(FATAL, __VA_ARGS__); exit(-1);}

如何做到这一点?

编辑: 作为上述的后续行动,有没有更好的方法来做到这一点?例如,通过避免使用宏。

【问题讨论】:

  • 根据你使用的语言选择一种语言标签会更好
  • 有什么理由实际使用宏,而不是可变参数模板?
  • @flowit 实际上没有理由。让我修改问题。您能否回答如何使用可变参数模板以及为什么它们更好?
  • 您可以在函数中检查致命并返回/退出。如果您想提高性能,请使用 if constexpr 将其作为模板参数

标签: c++ variadic-macros


【解决方案1】:

宏在 C++ 中大多是一个糟糕的选择——主要是因为它们与命名空间无关,并且可能在意外的地方生效。

也就是说 - 如何解决 OP 问题的示例,例如使用token pasting:

#include <iostream>

#define LOG(LEVEL, ...) LOG_##LEVEL(__VA_ARGS__)

#define LOG_INFO(...) log(Info, __VA_ARGS__)
#define LOG_WARN(...) log(Warn, __VA_ARGS__)
#define LOG_FATAL(...) do { log(Error, __VA_ARGS__); std::cerr << "Program aborted!\n"; } while (false)

enum Level { Info, Warn, Error };

void log(Level level, const char *text)
{
  static const char *levelText[] = { "INFO", "WARNING", "ERROR" };
  std::cerr << levelText[level] << ": " << text << '\n';
}

int main()
{
  LOG(INFO, "Everything fine. :-)");
  LOG(WARN, "Not so fine anymore. :-|");
  LOG(FATAL, "Things became worst. :-(");
}

输出:

INFO: Everything fine. :-)
WARNING: Not so fine anymore. :-|
ERROR: Things became worst. :-(
Program aborted!

Live Demo on coliru


后续问题的另一个示例 - 使用可变参数模板而不是宏:

#include <iostream>

enum Level { Info, Warn, Error, Fatal };

template <typename ...ARGS>
void log(Level level, ARGS&& ... args)
{
  static const char *levelText[] = { "INFO", "WARNING", "ERROR", "FATAL" };
  std::cerr << levelText[level] << ": ";
  (std::cerr << ... << args);
  std::cerr << '\n';
  if (level == Fatal) std::cerr << "Program aborted!";
}

int main()
{
  log(Info, "Everything fine.", ' ', ":-)");
  log(Warn, "Not so fine anymore.", ' ', ":-|");
  log(Error, "Things became bad.", ' ', ":-(");
  log(Fatal, "Things became worst.", ' ', "XXX");
}

输出:

INFO: Everything fine. :-)
WARNING: Not so fine anymore. :-|
ERROR: Things became bad. :-(
FATAL: Things became worst. XXX
Program aborted!

Live Demo on coliru

我必须承认我需要一些帮助来解包参数 - 可以在这里找到:
SO: What is the easiest way to print a variadic parameter pack using std::ostream?

【讨论】:

  • 是的。我明白为什么可变参数模板是要走的路:)
【解决方案2】:

扩展 Scheffs 的回答,这个将日志级别作为模板参数传递,允许使用 if constexpr(正如 JVApen 在他的评论中提到的那样)。您需要在编译时知道每个日志输出的相应级别,但我认为这不是问题。

enum Level { Info, Warn, Error, Fatal };

template<Level L, typename ...ARGS>
void log(ARGS&& ... args)
{
    static const char *levelText[] = { "INFO", "WARNING", "ERROR", "FATAL" };
    std::cerr << levelText[L] << ": ";
    (std::cerr << ... << args);
    std::cerr << '\n';
    if constexpr (L == Fatal)
        std::cerr << "Program aborted\n";
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多