Как рассчитать сумму, используя переменную универсальную лямбду в C++?

Я хотел написать общую функцию суммы, подобную следующей, но не в синтаксисе шаблона, а в лямбда-синтаксисе:

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

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

Поскольку общие лямбды отображаются в шаблонах, должно быть возможно сделать что-то вроде:

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

Но я не могу понять, как сделать рекурсию, используя лямбды. Поиск в этом и других местах не принес много пользы.

2 ответа

Решение

В C++14 вам на самом деле не нужна рекурсия, чтобы сделать это с помощью общих лямбд.
В качестве примера вы можете сделать это:

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

Тип возврата задается 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;
};

Ну, я предполагаю, что вам нужен тип, похожий на функтор, чтобы вычислить сумму, если вы используете лямбду. Если это так, то, я полагаю, вы могли бы написать небольшой обобщенный класс, чтобы занять место этой лямбды.

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

Я написал это таким образом, что тип возвращаемого значения может быть указан заранее. Но я полагаю, что вы могли бы изменить это, чтобы сделать это также общим.

Если это не было вашим намерением, пожалуйста, проигнорируйте этот ответ.

Другие вопросы по тегам