Suppose I have a printf
-like function (used for logging) utilizing perfect forwarding:
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());
}
(I didn't compile this but my real function follows this guideline)
How can I "unroll" the variadic argument into the boost::format variable f
?
I did some googling and found an interesting solution:
#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);
}
I don't know if this is a recommended solution but it seems to work. I don't like the hacky static_cast
usage, which seems necessary to silence the unused variable warnings on GCC.
As is usual with variadic templates, you can use recursion:
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;
}
Demo.
In C++17, simply (f % ... % std::forward<Arguments>(args));
will do.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With