并行 std::foreach 循环调用非静态 class 成员函数
Parallel std::foreach loop calling a non-static class member function
我想使用 C++17 并行 std::foreach
迭代涉及非静态 class 成员函数的操作。基本上,class 的每个对象都有自己的数据版本和作用于该数据的方法,我想 运行 该方法并行处理一系列值(输入到方法),更新内部数据。类似以下内容:
#include <iostream>
#include <vector>
#include <algorithm>
#include <execution>
class XYZ{
std::vector<double> xvec_;
double m;
public:
XYZ(std::vector<double> xvec) :xvec_{xvec}, m{0} {}
void add_to_m(double x) {
m += x;
}
void add_up(){
std::for_each(
std::execution::par,
std::begin(xvec_),
std::end(xvec_),
add_to_m);
}
void print_m() {
std::cout << m << std::endl;
}
};
int main(){
XYZ xyz1({1,2,3.5,7.8});
xyz1.add_up();
xyz1.print_m();
XYZ xyz2({1,2,8});
xyz2.add_up();
xyz2.print_m();
}
但这会产生以下错误:
error: invalid use of non-static member function ‘void XYZ::add_to_m(double)’
建议传递给 std::for_each
的函数必须是静态成员。使函数静态化不是一种选择,因为我希望每个对象都对自己的数据版本进行操作。我怎样才能实现这个想法?
编辑:如果您想获得代码的工作非并行版本,请将上面的 add_to_m
实现替换为
void add_up(){
for (auto &x : xvec_) add_to_m(x);
}
您需要将对象传递给 std::foreach
,其中包含对 this
XYZ
的一些引用。否则,它如何知道在哪个对象上调用该方法?一个 lambda 就可以了
std::foreach(std::execution::par, std::begin(xvec_), std::end(xvec_), [&](double x) { add_to_m(x); });
或者,如果您不想重复签名,std::bind_front
也有效
std::foreach(std::execution::par, std::begin(xvec_), std::end(xvec_), std::bind_front(&XYZ::add_to_m, this));
std::bind_front
生成一个像 lambda 一样的仿函数对象,因此 std::bind_front(f, args...)(args2...)
执行 std::invoke(f, args..., args2...)
。此外,非静态成员函数指针 f
上的 std::invoke(f, recv, args...)
和指向可以接收该方法的对象的指针 recv
充当 recv->*f(args...)
.
add_to_m
/this->add_to_m
本身并不是您可以用作此类对象的第一个 class“事物”。这只是C++的设计。
请注意,如果实际上 运行 并行,您当前的 add_to_m
会导致一场比赛。
我想使用 C++17 并行 std::foreach
迭代涉及非静态 class 成员函数的操作。基本上,class 的每个对象都有自己的数据版本和作用于该数据的方法,我想 运行 该方法并行处理一系列值(输入到方法),更新内部数据。类似以下内容:
#include <iostream>
#include <vector>
#include <algorithm>
#include <execution>
class XYZ{
std::vector<double> xvec_;
double m;
public:
XYZ(std::vector<double> xvec) :xvec_{xvec}, m{0} {}
void add_to_m(double x) {
m += x;
}
void add_up(){
std::for_each(
std::execution::par,
std::begin(xvec_),
std::end(xvec_),
add_to_m);
}
void print_m() {
std::cout << m << std::endl;
}
};
int main(){
XYZ xyz1({1,2,3.5,7.8});
xyz1.add_up();
xyz1.print_m();
XYZ xyz2({1,2,8});
xyz2.add_up();
xyz2.print_m();
}
但这会产生以下错误:
error: invalid use of non-static member function ‘void XYZ::add_to_m(double)’
建议传递给 std::for_each
的函数必须是静态成员。使函数静态化不是一种选择,因为我希望每个对象都对自己的数据版本进行操作。我怎样才能实现这个想法?
编辑:如果您想获得代码的工作非并行版本,请将上面的 add_to_m
实现替换为
void add_up(){
for (auto &x : xvec_) add_to_m(x);
}
您需要将对象传递给 std::foreach
,其中包含对 this
XYZ
的一些引用。否则,它如何知道在哪个对象上调用该方法?一个 lambda 就可以了
std::foreach(std::execution::par, std::begin(xvec_), std::end(xvec_), [&](double x) { add_to_m(x); });
或者,如果您不想重复签名,std::bind_front
也有效
std::foreach(std::execution::par, std::begin(xvec_), std::end(xvec_), std::bind_front(&XYZ::add_to_m, this));
std::bind_front
生成一个像 lambda 一样的仿函数对象,因此 std::bind_front(f, args...)(args2...)
执行 std::invoke(f, args..., args2...)
。此外,非静态成员函数指针 f
上的 std::invoke(f, recv, args...)
和指向可以接收该方法的对象的指针 recv
充当 recv->*f(args...)
.
add_to_m
/this->add_to_m
本身并不是您可以用作此类对象的第一个 class“事物”。这只是C++的设计。
请注意,如果实际上 运行 并行,您当前的 add_to_m
会导致一场比赛。