boost::具有可变模板参数的格式
boost::format with variadic template arguments
假设我有一个类似printf
的函数(用于日志记录),它利用了完美的转发:
template<typename... Arguments>
void awesome_printf(std::string const& fmt, Arguments&&... args)
{
boost::format f(fmt);
f % /* How to specify `args` here? */;
BlackBoxLogFunction(boost::str(f).c_str());
}
(我没有编译这个,但我的实际函数遵循这个准则)
如何将可变参数"展开"到boost::format变量f
中?
为了总结void.pointer的解决方案以及Praetorian、T.C.和Jarod42提出的提示,让我提供最终版本(在线演示)
#include <boost/format.hpp>
#include <iostream>
template<typename... Arguments>
std::string FormatArgs(const std::string& fmt, const Arguments&... args)
{
boost::format f(fmt);
std::initializer_list<char> {(static_cast<void>(
f % args
), char{}) ...};
return boost::str(f);
}
int main()
{
std::cout << FormatArgs("no argsn"); // "no args"
std::cout << FormatArgs("%s; %s; %s;n", 123, 4.3, "foo"); // 123; 4.3; foo;
std::cout << FormatArgs("%2% %1% %2%n", 1, 12); // 12 1 12
}
此外,正如T.C.所指出的,使用自C++17以来可用的fold表达式语法,FormatArgs函数可以以更简洁的方式重写
template<typename... Arguments>
std::string FormatArgs(const std::string& fmt, const Arguments&... args)
{
return boost::str((boost::format(fmt) % ... % args));
}
与可变模板一样,您可以使用递归:
std::string awesome_printf_helper(boost::format& f){
return boost::str(f);
}
template<class T, class... Args>
std::string awesome_printf_helper(boost::format& f, T&& t, Args&&... args){
return awesome_printf_helper(f % std::forward<T>(t), std::forward<Args>(args)...);
}
template<typename... Arguments>
void awesome_printf(std::string const& fmt, Arguments&&... args)
{
boost::format f(fmt);
auto result = awesome_printf_helper(f, std::forward<Arguments>(args)...);
// call BlackBoxLogFunction with result as appropriate, e.g.
std::cout << result;
}
演示。
在C++17中,只需(f % ... % std::forward<Arguments>(args));
即可。
我在谷歌上搜索了一下,发现了一个有趣的解决方案:
#include <iostream>
#include <boost/format.hpp>
template<typename... Arguments>
void format_vargs(std::string const& fmt, Arguments&&... args)
{
boost::format f(fmt);
int unroll[] {0, (f % std::forward<Arguments>(args), 0)...};
static_cast<void>(unroll);
std::cout << boost::str(f);
}
int main()
{
format_vargs("%s %d %d", "Test", 1, 2);
}
我不知道这是否是一个推荐的解决方案,但它似乎有效。我不喜欢破解的static_cast
用法,这似乎是让GCC上未使用的变量警告静音所必需的。
相关文章:
- C++fmt库,只使用格式说明符格式化单个参数
- clang 格式堆叠所有 if 语句参数,如果它们太长
- clang 格式:始终断开所有参数,每行一个
- 当超出列时,clang格式强制每个参数/参数拥有自己的行?
- 中断长代码 snprintf 格式和参数
- 使用宏定义打印格式参数
- 查找可变参数列表的字符串格式指定符
- 保留短 lambda 用作函数的中间参数,使用 clang 格式保持不变
- sscanf 格式参数不起作用
- sscanf_s:格式字符串"%d"需要类型为"int *"的参数,但可变参数 4 的类型为"WORD *"
- 格式“%lf”期望“ double *”类型的论点,但参数2具有“ poly term **”类型
- 警告:格式"%d"需要类型为"int*"的参数,但参数5的类型为"in
- C4477: 'fprintf' :格式字符串 '%s' 需要类型为"char *"的参数,但可变参数 1 的类型为"int *"
- 执行带有参数的 .bat 文件并以 C++ 格式读取控制台输出
- 警告:格式"%5f"需要类型"double",但参数3的类型为"int
- 如何将 GCC 的 printf 格式属性与 C++11 可变参数模板一起使用?
- "%p 格式说明符的参数类型是 'void*'"是什么意思?
- 默认参数之后的可变参数格式是否正确
- 抽象函数参数格式及其对性能的影响
- 程序的参数格式有标准吗?