为什么编译器会尝试实例化错误的 STL 模板? (BinaryOperation 而不是 UnaryOperation)

Why does the compiler try to instantiate the wrong STL template? (BinaryOperation instead of UnaryOperation)

我想将 std::transform 与并行执行策略一起使用。 documentation 告诉使用模板 (2):

template< class ExecutionPolicy,
          class ForwardIt1,
          class ForwardIt2,
          class UnaryOperation >
ForwardIt2 transform( ExecutionPolicy&& policy,
                      ForwardIt1 first1,
                      ForwardIt1 last1,
                      ForwardIt2 d_first,
                      UnaryOperation unary_op );

我的代码如下,和模板好像很吻合:

const std::vector<SimulatedBody>& bodies = m_data.back().m_bodies;
std::vector<SimulatedBody> updated_bodies;
std::transform(std::execution::par,
    bodies.begin(),
    bodies.end(),
    std::back_inserter(updated_bodies),
    [&](const SimulatedBody& body) {
        return body.updated(*quadtree, m_dt, m_force_algorithm_fn);
    });

body.updated的return类型是新的SimulatedBody:

SimulatedBody SimulatedBody::updated(
    const bh::Node& quadtree, float dt,
    const std::function<Vector2d(const Node&, const Body&)>&
        force_algorithm_fn = bh::compute_approximate_net_force_on_body) const

但是,当我编译时,它引发了以下错误:

/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/pstl/glue_algorithm_impl.h:325:44: error: argument may not have 'void' type
        [__op](_InputType __x, _OutputType __y) mutable { __y = __op(__x); },
                                           ^
/home/steddy/CLionProjects/barnes-hut/src/simulation/simple_simulator.cpp:35:8: note: in instantiation of function template specialization 'std::transform<const __pstl::execution::parallel_policy &, __gnu_cxx::__normal_iterator<const bh::SimulatedBody *, std::vector<bh::SimulatedBody>>, std::back_insert_iterator<std::vector<bh::SimulatedBody>>, (lambda at /home/steddy/CLionProjects/barnes-hut/src/simulation/simple_simulator.cpp:37:18)>' requested here
  std::transform(std::execution::par, bodies.begin(), bodies.end(),
       ^

从错误来看,似乎是编译器试图使用错误的模板;特别是带有 BinaryOperation 的一个。

我是不是漏掉了什么?

我使用的是 gcc 版本 12.1.1 20220507 (Red Hat 12.1.1-1)。

My code [...] seems to match the template:

它没有:

template< class ExecutionPolicy,
          class ForwardIt1,
          class ForwardIt2,
          class UnaryOperation >
ForwardIt2 transform( ExecutionPolicy&& policy,
                      ForwardIt1 first1,
                      ForwardIt1 last1,
                      ForwardIt2 d_first, // < here
                      UnaryOperation unary_op );

Parameters 部分,您链接的文档指定了目标范围的开始,参数 d_first,应该是一个前向迭代器:

Type requirements

  • [...]
  • ForwardIt1, ForwardIt2, ForwardIt3 must meet the requirements of LegacyForwardIterator.

您正在向它传递一个输出迭代器,即:

std::back_inserter(updated_bodies)

如果 SimulatedBody 是默认可构造的,您可以将 updated_bodies 的大小调整为 bodies 的大小并传递 updated_bodies.begin() (这是一个 random-access 迭代器,因此也是一个前向迭代器)到 std::transform:

const std::vector<SimulatedBody>& bodies = m_data.back().m_bodies;
std::vector<SimulatedBody> updated_bodies;
updated_bodies.resize(bodies.size()); // Resize output vector
std::transform(std::execution::par,
    bodies.begin(),
    bodies.end(),
    updated_bodies.begin(), // Pass iterator to first element
    [&](const SimulatedBody& body) {
        return body.updated(*quadtree, m_dt, m_force_algorithm_fn);
    });