- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我有一个 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)))
(as this
标记 log()
函数是第一个“隐藏”参数,我需要将参数索引移动一个)。这不起作用,因为如果失败并出现编译错误:
error: args to be formatted is not ‘...’
然后,我尝试将相同的属性添加到 true_log()
函数中。它编译,但实际上没有执行错误检查:我试图传递给 log()
一些无效的格式/变量组合,并且没有发出警告。也许这种检查“为时已晚”,或者换句话说,关于变量的信息已经在调用链中丢失了?
作为最后的手段,如果我用 __attribute__ ((format (printf, 2, 0)))
注释 log()
,我会收到有关错误格式的警告字符串,但不会针对无效的格式/变量组合发出诊断。
总结问题:如果我使用 C++11 的可变参数模板,如何从 GCC 进行完整的格式检查?
最佳答案
我不相信你可以。我敢打赌,如果格式字符串是 literal,GCC 只会验证格式字符串。这就是为什么将 format
属性放在 true_log
上不起作用的原因 - 该函数被调用时看起来(在语法上)类似于运行时确定的字符串。将它直接放在 log
上会规避这一点,但需要 format
属性来支持可变参数模板,而你证明它不支持。
我建议你看看更多的 C++-ish 方法来进行格式化输出。例如,boost::format
有点像 printf,但会动态验证参数类型的数量和类型是否与格式字符串匹配。但是,它不使用可变参数模板,而是一个接一个地使用(通过运算符 %)提供给它的参数。
关于c++ - 如何将 GCC 的 printf 格式属性与 C++11 可变参数模板一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12573968/
我是一名优秀的程序员,十分优秀!