将可变参数从一个函数传递到另一个函数?

问题描述

因为我不想在这里重复代码,所以我试图找出一种方法将每个记录器函数(例如调试、警告、信息等)的公共部分移到另一个函数中. 我自己尝试了一种幼稚的方法,但似乎无法正常工作。我想我需要直接传递一个 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,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();
  }
}

解决方法

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

使用 parameter packperfect forwarding

c=0
,

因此,由于使用可变参数模板看起来是解决此问题的最佳现代解决方案,因此我最终采用了以下解决方案,其中不再需要对每个日志功能(调试、警告等)进行专门化处理。自从我使用 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();
  }