如何简化这些变进函数

How to simplify these variadic functions?

本文关键字:函数 何简化      更新时间:2023-10-16

我编写了一个Logger类,用于将信息转储到文件中。下面的代码是Logger的一个缩影。函数看起来几乎是一样的…但我不知道怎么化简。你能让它更优雅吗?

我的早期版本使用可变宏来实现这个目标。后来我注意到这两个数据,文件指针和缩进级别,可以被封装到一个类中,这样我就不需要每次都通过(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);
}

就像你不把你的参数转发给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,试着使用一个有完美转发的模板

我会写这样的东西(是的,也使用宏):

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");
  }
}

您可以将这些函数减少为可变宏,这样您就可以摆脱对va_startva_end的冗余调用:

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

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

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

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