Boost logo

Boost :

Subject: [boost] Metaprogramming: parameter pack expansion/evaluation trick
From: Antony Polukhin (antoshkka_at_[hidden])
Date: 2015-07-03 02:16:44


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 <typename... Args>
void print(Args&&... a) {
    // print each a on a separate line
}

There's a known trick to do that:

template <typename... Args>
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<typename... Args>
void print(Args&&... a) {
    expand_if<Args...> {
        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<typename... Args>
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<typename... Args>
float sum(Args&&... args) {
    float res = 0;
    expand_if<Args...> {
        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<typename... Args>
void print(Args&&... a) {
    std::cout << a << '\n'...;
}

P.S.: There was a nicer solution that newer required "_if<Args..>" :

namespace detail {
    struct expand_impl final {
        template <class... Arg>
        constexpr inline
            expand_impl(Arg&&...) noexcept
        {}
    };
}

template <class... Arg>
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

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk