如何在 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;
};
我想写一个像下面这样的通用求和函数,但不是用模板语法,而是用 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;
};