Search code examples
c++genericslambdac++14variadic

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


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.


Solution

  • 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;
    };