Metaprogramming: parameter pack expansion/evaluation trick
Hi,
Straight to the problem. Consider the situation, were a function accepts
parameter pack and something need to be done with each argument (for
example, we want to print each argument on a new line):
template
C++1z will have fold expressions for this:
(std::cout << a << '\n', ...);
Add optional (void) cast for the paranoid.
Also, your implementation doesn't work if the type of the expression is
`void`, as far as I can see.
On Fri, Jul 3, 2015 at 2:16 AM, Antony Polukhin
Hi,
Straight to the problem. Consider the situation, were a function accepts parameter pack and something need to be done with each argument (for example, we want to print each argument on a new line):
template
void print(Args&&... a) { // print each a on a separate line } There's a known trick to do that:
template
void print(Args&&... a) { (void) (int []){ 0, (std::cout << a << std::endl, 0)... }; } But the syntax is not very readable (and I always forget it and search for an example in Internet). I've tried to improve the syntax, and here's the result:
template
void print(Args&&... a) { expand_if { std::cout << a << '\n'... }; } Compete source could be found here: http://coliru.stacked-crooked.com/view?id=c2c59f22574671e5
Here's some more usage examples:
template
void printer_int(Args&&... args) { expand { std::cout << std::abs(args) << std::endl..., std::cout << "Printing once again all the numbers: " << std::endl, std::cout << " Once again " << std::abs(args) << std::endl..., std::cout << "EOF Printing once again all the numbers." << std::endl }; } template
float sum(Args&&... args) { float res = 0; expand_if { res += args... }; return res; }
I hope this would be helpful for someone or it could be used as an argument for a proposal to extend C++ and allow simpler syntax:
template
void print(Args&&... a) { std::cout << a << '\n'...; } P.S.: There was a nicer solution that newer required "_if
" : namespace detail { struct expand_impl final { template
constexpr inline expand_impl(Arg&&...) noexcept {} }; } template
using expand = detail::expand_impl; But unfortunately there's no way to force the compiler to evaluate expressions in constructor call from left to right. So it did not work on GCC (but work on Clang).
-- Best regards, Antony Polukhin
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
namespace detail { struct expand_impl final { template
constexpr inline expand_impl(Arg&&...) noexcept {} }; } template
using expand = detail::expand_impl; But unfortunately there's no way to force the compiler to evaluate expressions in constructor call from left to right. So it did not work on GCC (but work on Clang).
There is. Just use {} and it's guaranteed to evaluate the args from left to right.
But unfortunately there's no way to force the compiler to evaluate expressions in constructor call from left to right. So it did not work on GCC (but work on Clang).
« []
There is. Just use {} and it's guaranteed to evaluate the args from left to right.
Also, just as a note, the Fit library has `apply_eval` that will evaluate the arguments in order from left to right, even on compilers that don't guarantee the order of {} yet: http://fit.readthedocs.org/en/latest/apply_eval/index.html Paul -- View this message in context: http://boost.2283326.n4.nabble.com/Metaprogramming-parameter-pack-expansion-... Sent from the Boost - Dev mailing list archive at Nabble.com.
participants (4)
-
Antony Polukhin
-
Paul Fultz II
-
Tim Song
-
TONGARI J