【发布时间】:2012-09-16 10:34:05
【问题描述】:
我有一个 C++ 类,它是日志系统的前端。它的日志功能是使用 C++11 的可变参数模板实现的:
template <typename... Args>
void Frontend::log(const char *fmt, Args&&... args) {
backend->true_log(fmt, std::forward<Args>(args)...);
}
每个日志记录后端都实现了自己的true_log 版本,除其他外,它使用转发参数调用vsnprintf。例如:
void Backend::true_log(const char *fmt, ...) {
// other stuff..
va_list ap;
va_start(ap, fmt);
vsnprintf(buffer, buffer_length, fmt, ap);
va_end(ap);
// other stuff..
}
一切都很好,我很高兴。
现在,我想对log() 参数添加一个静态检查:具体来说,我想使用 GCC 的 printf 格式属性。
我首先用__attribute__ ((format (printf, 2, 3))) 标记log() 函数(因为this 是第一个“隐藏”参数,我需要将参数索引移动一个)。这不起作用,因为如果失败并出现编译错误:
error: args to be formatted is not ‘...’
然后,我尝试将相同的属性添加到true_log() 函数。它编译,但实际上没有执行错误检查:我试图传递给log()一些无效的格式/变量组合,并且没有发出警告。也许这种检查“为时已晚”,或者换句话说,关于变量的信息已经在调用链中丢失了?
作为最后的手段,如果我用__attribute__ ((format (printf, 2, 0))) 注释log(),我会收到有关错误格式字符串的警告,但不会针对无效的格式/变量组合发出诊断。
问题总结:如果我使用 C++11 的可变参数模板,如何从 GCC 进行完整的格式检查?
【问题讨论】:
-
既然 vsnprintf() 不能处理比老派 ... 所能做的更多的事情,为什么要首先使用可变参数模板呢?
-
当您只是丢弃类型信息时,为什么还要使用可变参数模板?只需将
true_log()设为您真正的日志记录功能。 -
或者让
Frontend::log接受一个可变参数...
标签: c++ gcc c++11 variadic-templates function-attributes