C++14 中这个 C++17 折叠表达式的一个很好的替代方案是什么?
What is a good alternative to this C++17 fold expression in C++14?
这是 C++17 中基于 lambda 的漂亮、简洁的折叠表达式:
#include <cstdint>
using ::std::uint64_t;
constexpr auto sumsquares = [](auto... n) { return ((n * n) + ...); };
// I want this to work.
uint64_t foo(uint64_t x, uint64_t y, uint64_t z)
{
return sumsquares(x, y, z);
}
// And this too
double bar(uint64_t x, double y)
{
return sumsquares(x, y);
}
我写了这段代码来在 C++14 中做类似的事情,但它似乎比它应该的更冗长和混乱。我正在寻找一种以相对清晰简洁的方式在 C++14 中表达上述 C++17 代码的方法。准确地说,我希望能够编写代码,使用函数调用之类的语法为某个已知维数的向量计算向量大小的平方。但是维度的数量可以任意变化。并且坐标系的各个分量的精确数值类型也可以是任意的并且可能是异构的。但是在 C++14 中处理 C++17 折叠表达式的通用方法是理想的。
#include <cstdint>
#include <utility>
using ::std::uint64_t;
namespace {
static constexpr struct {
template <typename T>
auto operator()(T && n) const
{
return n*n;
}
template <typename T, typename... S>
auto operator()(T && n, S && ... s) const
{
return (n * n) + (*this)(::std::forward<S>(s)...);
}
} sumsquares;
}
// I want this to work.
uint64_t foo(uint64_t x, uint64_t y, uint64_t z)
{
return sumsquares(x, y, z);
}
// And this too
double bar(uint64_t x, double y)
{
return sumsquares(x, y);
}
是的,您实际上可以通过定义多个对象的通用总和来做更简单、更通用的事情:
template<typename T>
T sum(T x)
{
return x;
}
template<typename U, typename... T>
auto sum(U x, T... nums)
{
return x + sum(nums...);
}
template<typename... T>
auto sum_of_squares(T... nums)
{
auto square = [](auto x) { return x * x; };
return sum(square(nums)...);
}
Live demo here, and here 你可以看到生成的程序集(这似乎是最佳的)。虽然我个人非常不喜欢 auto
作为 return 类型,但这里可以避免使用非常复杂的表达式来获取类型。
一种可能的非递归写法sum()
如下
template <typename ... Ts>
auto sum (Ts ... ts)
{
using unused = int[];
std::common_type_t<Ts...> ret {};
(void)unused{ 0, (ret += ts, 0)... };
return ret;
}
给定一个sum()
函数,sum_of_squares()
可以简单地写成如下
template <typename ... Ts>
auto sum_of_squares (Ts ... ts)
{ return sum( (ts*ts)... ); }
#include <utility>
#include <functional>
template<class F, class A0>
auto fold(F&&, A0&& a0) {
return std::forward<A0>(a0);
}
template<class F, class A0, class...As>
auto fold(F&& f, A0&&a0, As&&...as) {
return f(std::forward<A0>(a0), fold(f, std::forward<As>(as)...));
}
auto sum_squares=[](auto&&...args) {
return fold(std::plus<>{}, (args * args)... );
};
这是 C++17 中基于 lambda 的漂亮、简洁的折叠表达式:
#include <cstdint>
using ::std::uint64_t;
constexpr auto sumsquares = [](auto... n) { return ((n * n) + ...); };
// I want this to work.
uint64_t foo(uint64_t x, uint64_t y, uint64_t z)
{
return sumsquares(x, y, z);
}
// And this too
double bar(uint64_t x, double y)
{
return sumsquares(x, y);
}
我写了这段代码来在 C++14 中做类似的事情,但它似乎比它应该的更冗长和混乱。我正在寻找一种以相对清晰简洁的方式在 C++14 中表达上述 C++17 代码的方法。准确地说,我希望能够编写代码,使用函数调用之类的语法为某个已知维数的向量计算向量大小的平方。但是维度的数量可以任意变化。并且坐标系的各个分量的精确数值类型也可以是任意的并且可能是异构的。但是在 C++14 中处理 C++17 折叠表达式的通用方法是理想的。
#include <cstdint>
#include <utility>
using ::std::uint64_t;
namespace {
static constexpr struct {
template <typename T>
auto operator()(T && n) const
{
return n*n;
}
template <typename T, typename... S>
auto operator()(T && n, S && ... s) const
{
return (n * n) + (*this)(::std::forward<S>(s)...);
}
} sumsquares;
}
// I want this to work.
uint64_t foo(uint64_t x, uint64_t y, uint64_t z)
{
return sumsquares(x, y, z);
}
// And this too
double bar(uint64_t x, double y)
{
return sumsquares(x, y);
}
是的,您实际上可以通过定义多个对象的通用总和来做更简单、更通用的事情:
template<typename T>
T sum(T x)
{
return x;
}
template<typename U, typename... T>
auto sum(U x, T... nums)
{
return x + sum(nums...);
}
template<typename... T>
auto sum_of_squares(T... nums)
{
auto square = [](auto x) { return x * x; };
return sum(square(nums)...);
}
Live demo here, and here 你可以看到生成的程序集(这似乎是最佳的)。虽然我个人非常不喜欢 auto
作为 return 类型,但这里可以避免使用非常复杂的表达式来获取类型。
一种可能的非递归写法sum()
如下
template <typename ... Ts>
auto sum (Ts ... ts)
{
using unused = int[];
std::common_type_t<Ts...> ret {};
(void)unused{ 0, (ret += ts, 0)... };
return ret;
}
给定一个sum()
函数,sum_of_squares()
可以简单地写成如下
template <typename ... Ts>
auto sum_of_squares (Ts ... ts)
{ return sum( (ts*ts)... ); }
#include <utility>
#include <functional>
template<class F, class A0>
auto fold(F&&, A0&& a0) {
return std::forward<A0>(a0);
}
template<class F, class A0, class...As>
auto fold(F&& f, A0&&a0, As&&...as) {
return f(std::forward<A0>(a0), fold(f, std::forward<As>(as)...));
}
auto sum_squares=[](auto&&...args) {
return fold(std::plus<>{}, (args * args)... );
};