如何简化这些可变函数?

时间:2014-05-30 14:05:53

标签: c++ variadic variadic-functions

我写了一个Logger类,用于将信息转储到文件中。以下代码是Logger的缩影。功能看起来几乎相同......但我不知道如何简化它。你能让它更优雅吗?

My earlier version使用了varadic宏来实现这一目标。后来我注意到这两个数据,文件指针和缩进级别可以封装到一个类中,因此我不需要每次都传递(FILE *fp, size_t indent)(Xml_Logger &logger)就够了。

所以我希望我可以使用会员功能,否则就像我回滚......

void ind_print(const char *format, ...) {
  print_indent();

  va_list args;
  va_start(args, format);
  vprintf(format, args);
  va_end(args);
}

void ind_println(const char *format, ...) {
  print_indent();

  va_list args;
  va_start(args, format);
  vprintf(format, args);
  va_end(args);

  printf("\n");
}

void print(const char *format, ...) {
  va_list args;
  va_start(args, format);
  vprintf(format, args);
  va_end(args);
}

void println(const char *format, ...) {
  va_list args;
  va_start(args, format);
  vprintf(format, args);
  va_end(args);

  printf("\n");
}

更新:看看这两个功能。我希望println可以调用print,但遗憾的是它不能。不是吗?

void Xml_Logger::print(const char *format, ...) const {
  print_indent();
  va_list args;
  va_start(args, format);
  vfprintf(fp, format, args);
  va_end(args);
}

void Xml_Logger::println(const char *format, ...) const {
  print_indent();
  va_list args;
  va_start(args, format);
  vfprintf(fp, format, args);
  va_end(args);
  fputc('\n', fp);
}

4 个答案:

答案 0 :(得分:1)

我会写类似的东西(是的,也是使用宏):

print.h:

void _print(int indent, int eol, const char *format, ...);
#define print(format, ...) _print(0, 0, format, __VA_ARGS__)
#define println(format, ...) _print(0, 1, format, __VA_ARGS__)
#define ind_print(format, ...) _print(1, 0, format, __VA_ARGS__)
#define ind_println(format, ...) _print(1, 1, format, __VA_ARGS__)

print.c:

void _print(int indent, int eol, const char *format, ...) {
  va_list args;

  if (ident) {
    print_indent();
  }

  va_start(args, format);
  vprintf(format, args);
  va_end(args);

  if (eol) {
     printf("\n");
  }
}

答案 1 :(得分:1)

就像你没有将你的论点转发给fprintf,这是变量,但vfprintf,你会在你的情况下做同样的事。

void Xml_Logger::master_print(bool indent, bool newline, const char* format, va_list& args) const
{
  if (indent) print_indent();
  vfprintf(fp, format, args);
  if (newline) fputc('\n', fp);
}

void Xml_Logger::print(const char *format, ...) const
{
  va_list args;
  va_start(args, format);
  master_print(true, false, format, args);
  va_end(args);
}

void Xml_Logger::println(const char *format, ...) const
{
  va_list args;
  va_start(args, format);
  master_printf(true, true, format, args);
  va_end(args);
}

但不幸的是,这需要在每个包装器中重复va_list个东西。因此,如果你有C ++ 11,请尝试使用a template with perfect forwarding

答案 2 :(得分:0)

您可以将这些功能减少为可变宏,这样您就可以摆脱对va_startva_end的多余调用:

#define IND_PRINT(fmt, ...) { \
    print_indent(); \
    printf(fmt, ## __VA_ARGS__); \
}

然后你应该将每个宏放在一个头文件中,这样它们对项目的其余部分都是可见的。

答案 3 :(得分:0)

您可以使用C ++ 11可变参数模板转发可变数量的参数:

template<typename ...TArgs>
void Xml_Logger::println(const char *format, TArgs&& ...args) const
{
  print(format, std::forward(args)...);
  fputc('\n', fp);
}