【问题标题】:Passing variadic parameters from a function to another?将可变参数从一个函数传递给另一个?
【发布时间】:2020-12-29 20:50:41
【问题描述】:

由于我不想在这里重复代码,我试图找出一种方法将每个记录器函数(例如调试、警告、信息等)的公共部分移动到另一个函数中. 我自己尝试过一种天真的方法,但似乎不能正常工作。我想我需要直接传递va_list,但这样做我不知道是否值得一开始就创建一个单独的函数。关于如何实现这一目标的任何想法/建议?

原创

void ConsoleLogger::debug(const char *fmt...)
{
  if (static_cast<uint8_t>(LogLevel::DEBUG) <= static_cast<uint8_t>(configuration.priority))
  {
    va_list args;
    char log_text[LOG_MAX_LENGTH];

    va_start(args, fmt);
    vsnprintf(log_text, LOG_MAX_LENGTH, fmt, args);
    va_end(args);

    std::cout << get_time_as_string() + " [DEBUG] " + log_text + "\n";
    std::cout.flush();
  }
}

我的镜头没有按预期工作,因为 log_text 填充了错误/随机字符,而在原始文件中它打印了正确的字符串。

const std::string Logger::get_log_text(const char *fmt...) const
{
  va_list args;
  char log_text[LOG_MAX_LENGTH];

  va_start(args, fmt);
  vsnprintf(log_text, LOG_MAX_LENGTH, fmt, args);
  va_end(args);
  return std::string(log_text);
}

void ConsoleLogger::debug(const char *fmt...)
{
  if (static_cast<uint8_t>(LogLevel::DEBUG) <= static_cast<uint8_t>(configuration.priority))
  {
    std::string log_text = get_log_text(fmt);
    std::cout << get_time_as_string() + " [DEBUG] " + log_text + "\n";
    std::cout.flush();
  }
}

【问题讨论】:

  • FWIW,您应该考虑使用 variadic templates 而不是老式的 C 变量函数。它们在类型系统上的表现要好得多,而且我发现它们更易于使用。
  • ...它们甚至可以被转发!
  • 什么不能按预期工作?期望什么?你的问题我不清楚。
  • @Barnercart 这个问题被骗了。请参阅此处以获取答案:stackoverflow.com/questions/150543/…
  • 我正在运行不同的 Logger 实现,如 ConsoleLogger、FileLogger 等,它们都使这些日志记录功能过载。这是否可以通过 viariadic 模板函数实现?基类有那些虚拟的,据我所知,C++ 目前不允许虚拟模板成员函数。

标签: c++ variadic-functions


【解决方案1】:

好吧,首先这个答案并没有从字面上回答这个问题,因为我对C可变参数函数不是特别熟悉,但它可以解决你的实际问题,并且在C++中也更推荐。

使用parameter packperfect forwarding

template <class ...args_t>
const std::string get_log_text(const char *fmt, args_t &&...args)
{
    char log_text[LOG_MAX_LENGTH];
    sprintf(log_text, fmt, std::forward<args_t>(args)...);
    return std::string(log_text);
}

template <class ...args_t>
void debug(const char *fmt, args_t &&...args)
{
    if (static_cast<uint8_t>(LogLevel::DEBUG) <= static_cast<uint8_t>(configuration.priority))
    {
        std::string log_text = get_log_text(fmt, std::forward<args_t>(args)...);
        std::cout << get_time_as_string() + " [DEBUG] " + log_text + "\n";
        std::cout.flush();
    }
}

【讨论】:

  • 感谢您的努力,我最终得到了一个稍微不同的解决方案,抛弃了旧的 C 风格实现。
【解决方案2】:

因此,由于使用可变参数模板看起来是解决此问题的最佳现代解决方案,因此我最终得到了以下解决方案,其中每个日志功能(调试、警告等)不再需要专门化。自从我使用 c++17 编译以来,我从 this 建议中获得了使用折叠表达式的灵感。

  template <typename... T> void debug(const T &...args)
  {
    if (static_cast<uint8_t>(LogLevel::DEBUG) <= static_cast<uint8_t>(configuration.priority))
    {
      std::string final_text = "[DEBUG] " + get_log_text(args...);
      log(final_text); // this is specialized in every Logger derived class depending on the type
    }
  }

  template <typename... T> const std::string get_log_text(T &...args) const
  {
    std::ostringstream log_text;
    ((log_text << std::forward<T>(args)), ...);
    return log_text.str();
  }

【讨论】:

    猜你喜欢
    • 2018-10-22
    • 1970-01-01
    • 2011-11-10
    • 1970-01-01
    • 1970-01-01
    • 2020-05-03
    • 2012-08-02
    • 2012-09-25
    • 2020-10-03
    相关资源
    最近更新 更多