How to calculate sum using variadic generic lambda in C++?

904 views Asked by At

I wanted to write a generic sum function like the following one but not in template syntax but in lambda syntax:

template<typename T>
auto Sum(T lastSummand)
{
    return lastSummand;
}

template<typename T, typename... Ts>
auto Sum(T firstSummand, Ts... restSummands)
{
    return firstSummand + Sum(restSummands...);
}

Because generic lambdas are mapped to templates it should be possible to do something like:

auto sum = [](auto firstSummand, auto... restSummands) { ... };

But I cannot figure out how to do the recursion using lambdas. Searching in this and other locations did not bring forward much.

2

There are 2 answers

5
skypjack On BEST ANSWER

In C++14 you don't actually need recursion to do that with generic lambdas.
As an example, you can do this:

#include<type_traits>
#include<iostream>

int main() {
    auto l = [](auto... values) {
        std::common_type_t<decltype(values)...> ret = {};
        decltype(ret) _[] = { (ret += values)... };
        (void)_;
        return ret;
    };

    auto v = l(0, 0., 5, 4.2);
    std::cout << v << std::endl;
}

Return type is given by the std::common_type_t of the given pack.
The rest of the code contains the common pattern usually used while waiting for fold expressions.

In C++17 it will become:

#include<iostream>

int main() {
    auto l = [](auto... values) { return (values + ...); };
    auto v = l(0, 0., 5, 4.2);
    std::cout << v << std::endl;
}

See it on wandbox.

If you want to verify on the fly that given parameters are all of arithmetic types, you can use the bool trick as it follows:

auto l = [](auto... values) {
    static_assert(
        std::is_same<
            std::integer_sequence<bool, true, std::is_arithmetic<decltype(values)>::value...>,
            std::integer_sequence<bool, std::is_arithmetic<decltype(values)>::value..., true>
        >::value, "!"
    );

    std::common_type_t<decltype(values)...> ret = {};
    decltype(ret) _[] = { (ret += values)... };
    (void)_;
    return ret;
};
2
SLC On

Well, i'm assuming you need a functor-like type to calculate the sum if you're using the lambda. If that's the case then I suppose you could write a small generic class to take the place of that lambda.

template < typename T > struct Sum
{
    template < typename U >
    T operator () (U v) const noexcept
    {
        return static_cast< T >(v);
    }

    template < typename U, typename... Values >
    T operator () (U v, Values&&... vs) const noexcept
    {
        return static_cast< T >(v) + (*this)(std::forward< Values >(vs)...);
    }
};

And used as:

auto sum = Sum< int >();
printf("%d\n", sum(23, 4.0, true, 7));

I wrote it in such way that the return type can be specified in advance. But I suppose you could adjust it to make that generic as well.

If this was not your intention then please ignore this answer.