Forwards and return type(s) in functional-like reduce function

Viewed 222

I need to create a reduce function similar to std::reduce, but instead of working on containers, this function should work on variadic parameters.

This is what I currently have:

template <typename F, typename T>
constexpr decltype(auto) reduce(F&&, T &&t) {
    return std::forward<T>(t);
}

template <typename F, typename T1, typename T2, typename... Args>
constexpr decltype(auto) reduce(F&& f, T1&& t1, T2&& t2, Args&&... args) {
    return reduce(
        std::forward<F>(f),
        std::forward<F>(f)(std::forward<T1>(t1), std::forward<T2>(t2)),
        std::forward<Args>(args)...);
}

The following works as expected:

std::vector<int> vec;
decltype(auto) u = reduce([](auto &a, auto b) -> auto& {
        std::copy(std::begin(b), std::end(b), std::back_inserter(a));
        return a;
    }, vec, std::set<int>{1, 2}, std::list<int>{3, 4}, std::vector<int>{5, 6});

assert(&vec == &u); // ok
assert(vec == std::vector<int>{1, 2, 3, 4, 5, 6}); // ok

But the following does not work:

auto u = reduce([](auto a, auto b) {
        std::copy(std::begin(b), std::end(b), std::back_inserter(a));
        return a;
    }, std::vector<int>{}, std::set<int>{1, 2}, 
    std::list<int>{3, 4}, std::vector<int>{5, 6});

This basically crashes - To make this work, I need to e.g. change the first definition of reduce to:

template <typename F, typename T>
constexpr auto reduce(F&&, T &&t) {
    return t;
}

But if I do so, the first snippet does not work anymore.

The problem problem lies in the forwarding of the parameters and the return type of the reduce function, but I can find it.

How should I modify my reduce definitions to make both snippets work?

3 Answers
Related