boost::具有可变模板参数的格式

boost::format with variadic template arguments

本文关键字:参数 格式 boost      更新时间:2023-10-16

假设我有一个类似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上未使用的变量警告静音所必需的。