如何在 C++ 中使用可变通用 lambda 计算总和?

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

我想写一个像下面这样的通用求和函数,但不是用模板语法,而是用 lambda 语法:

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

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

因为通用的 lambda 被映射到模板,所以应该可以做类似的事情:

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

但我不知道如何使用 lambda 进行递归。在此和其他位置进行搜索并没有带来太多结果。

好吧,如果您使用的是 lambda,我假设您需要类似仿函数的类型来计算总和。如果是这样的话,那么我想你可以写一个小的通用 class 来代替那个 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)...);
    }
};

并用作:

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

我是这样写的,可以提前指定return类型。但我想你也可以调整它以使其通用。

如果这不是您的本意,请忽略此回答。

在 C++14 中,您实际上不需要递归来使用通用 lambda 执行此操作。
例如,您可以这样做:

#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 类型由给定包的 std::common_type_t 给出。
其余代码包含等待 折叠表达式 .

时通常使用的常见模式

在 C++17 中它将变为:

#include<iostream>

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

wandbox 上查看。

如果你想即时验证给定的参数都是算术类型,你可以使用 bool 技巧,如下所示:

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