Как рассчитать сумму, используя переменную универсальную лямбду в 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));
Я написал это таким образом, что тип возвращаемого значения может быть указан заранее. Но я полагаю, что вы могли бы изменить это, чтобы сделать это также общим.
Если это не было вашим намерением, пожалуйста, проигнорируйте этот ответ.