当为不同的迭代器和 init 类型调用 std::reduce 时,Visual Studio 中出现编译器错误

0xb*_*00d 0 c++ reduce c++20

请考虑以下简单的代码片段:

template<typename T>
struct point2{ T x, y; };

template<typename T>
std::complex<T> foo(std::vector<point2<T>> const& x)
{
    std::reduce(std::execution::par_unseq, x.begin(), x.end(), std::complex<T>{},
        [&](std::complex<T> const& first, point2<T> const& second) {
            return first + std::complex<T>{ second.x, second.y };
        });
}
Run Code Online (Sandbox Code Playgroud)

使用 Visual Studio 2022(C++ 语言设置为 C++20)时,我收到错误消息

'int foo::<lambda_1>::operator ()(const std::complex &,const point2 &) const': 无法将参数 2 从 'std::complex' 转换为 'const point2 &'

这里出了什么问题?定义中的迭代器指向的类型似乎std::reduce需要与所选的初始值相同。但这似乎不是 C++ 标准中描述的要求。我错过了什么吗?

Yks*_*nen 5

std::reduce允许以任意顺序对集合中的元素进行分组和重新排列,以实现更有效的实现。要求 和 的所有组合*first都是init有效参数binary_op(引自27.10.4 Reduce #5):

\n
\n

授权范围:全部

\n
binary_\xc2\xadop(init, *first),\nbinary_\xc2\xadop(*first, init),\nbinary_\xc2\xadop(init, init), and\nbinary_\xc2\xadop(*first, *first)\n
Run Code Online (Sandbox Code Playgroud)\n

可转换为 T。

\n
\n

您似乎正在寻找std::accumulate,它具有相同的效果,但确保保留评估顺序。

\n
\n

为了保持使用的可能性std::execution::par_unseq,您可以尝试在point2和之间添加转换std::complex

\n
template<typename T>\nstruct point2{ \n    T x, y; \n    point2(const std::complex<T>& c): x{c.real()}, y{c.imag()} {}\n\n    // Or replace first argument in lambda with point2<T>\n    // instead of this conversion operator, and adjust the rest accordingly\n    operator std::complex<T>() { return {x, y};}\n};\n
Run Code Online (Sandbox Code Playgroud)\n

尽管我不确定转换是否不会消除并行化算法的好处,但您应该在使用这两个版本之前对其进行测试和分析。

\n