Boost :: format with variable template arguments

Suppose I have a printf function (used for logging) that uses 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 did not compile this, but my real function follows this guide)

How can I β€œexpand” a variable argument into a boost :: format f variable?

+6
source share
3 answers

As usual with variable 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, eg std::cout << result; } 

Demo


In C ++ 17, it will execute simply (f % ... % std::forward<Arguments>(args)); .

+10
source

I did some search queries 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 the recommended solution, but it seems to work. I don't like the use of hacky static_cast , which seems necessary to disable the warnings of an unused variable in GCC.

+7
source

Just to summarize the void.pointer solution and the hints suggested by Praetorian , TC and Jarod42 , let me provide the final version ( online demo )

 #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 args\n"); // "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 } 

In addition, as TC noted , using fold expression syntax available with C ++ 17, the FormatArgs function can be rewritten in a more concise way

 template<typename... Arguments> std::string FormatArgs(const std::string& fmt, const Arguments&... args) { return boost::str((boost::format(fmt) % ... % args)); } 
+4
source

Source: https://habr.com/ru/post/975336/


All Articles