C++ 在函数中使用多态函子
我需要一个函数来计算GPU上几个变量的“数学”函数。我决定使用推力及其C++ 在函数中使用多态函子,c++,cuda,thrust,C++,Cuda,Thrust,我需要一个函数来计算GPU上几个变量的“数学”函数。我决定使用推力及其zip_迭代器将变量打包到一个元组中,并将我的数学函数作为每个的函数foκ。但我想有一个通用函数,可以计算不同的“数学”函数。所以,我需要在函数中传递这个函子 我认为,要完成这项任务,我应该使用不同版本的operator()(Tuple t)实现一些简单的函子层次结构(只有基类)。例如,函子可以如下所示: struct Func { template <typename Tuple> __host_
zip_迭代器
将变量打包到一个元组中,并将我的数学函数作为每个的函数foκ。但我想有一个通用函数,可以计算不同的“数学”函数。所以,我需要在函数中传递这个函子
我认为,要完成这项任务,我应该使用不同版本的operator()(Tuple t)
实现一些简单的函子层次结构(只有基类)。例如,函子可以如下所示:
struct Func {
template <typename Tuple>
__host__ __device__
void operator()(Tuple arg) {
thrust::get<1>(arg) = 0;
}
};
strust f1 : public Func {
...
};
strust f2 : public Func {
...
};
但是有了这样的定义,我就不能把f1
或f2
传递到它里面。我如何正确定义它 您似乎希望将用户定义或用户可选择的函数传递给推力,以便在函子中进行计算。基于这一点,我认为一个可能的答案是非常相似的张贴,但我会提出一些其他意见
我不认为你真的在问这个问题,但我认为用主机类表示,最终将对象传递给设备以在推力::设备_向量
中使用基本上是不可能的,因为尽管这并不完全明显,如果我在主机上创建了一个适当的对象数组,然后尝试在asch::device\u vector
中以多态方式使用它们,这实际上就是我要做的事情。至少,我不能在丛林中挣扎。当然,您可以在设备代码中使用多态性,前提是在设备上正确创建了对象,以便可以正确分配它们的虚拟函数表。可能也有兴趣。如果您想查看在设备对象上使用多态性的示例,请查看我的答案。它演示了使用对象本身定义要在其上执行的函数的思想。(不过,我还是不认为你是这么想的。)
根据您编辑的问题,您似乎希望传递函数的地址,以便在函子中使用。这对于CUDA来说也是不可能的(至少以一种直截了当的方式),因为这种限制可以通过调用“初始化内核”来解决,该内核填充设备函数指针表以用于设备代码,但我认为最终效果并不比我在下面第3节中提出的好
您可以传递用户可选择的函数索引,以便在设备代码中使用李>
下面的示例演示了最后一个想法:
#include <thrust/device_vector.h>
#include <thrust/sequence.h>
#include <thrust/copy.h>
#include <thrust/for_each.h>
#include <thrust/iterator/zip_iterator.h>
#include <iostream>
#include <math.h>
__host__ __device__ float f1(float x)
{
return sinf(x);
}
__host__ __device__ float f2(float x)
{
return cosf(x);
}
struct select_functor
{
unsigned fn;
select_functor(unsigned _fn) : fn(_fn) {};
template <typename Tuple>
__host__ __device__
void operator()(const Tuple &t) {
if (fn == 1) thrust::get<1>(t) = f1(thrust::get<0>(t));
else if (fn == 2) thrust::get<1>(t) = f2(thrust::get<0>(t));
else thrust::get<1>(t) = 0;
}
};
int main(void)
{
unsigned ufn = 1;
const unsigned N = 8;
thrust::device_vector<float> data(N), result(N);
// initilaize to some values
thrust::sequence(data.begin(), data.end(), 0.0f, (float)(6.283/(float)N));
std::cout<< "x: " << std::endl;
thrust::copy(data.begin(), data.end(), std::ostream_iterator<float>(std::cout, " "));
thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(data.begin(), result.begin())),thrust::make_zip_iterator(thrust::make_tuple(data.end(),result.end())),select_functor(ufn));
std::cout<< std::endl << "sin(x): " << std::endl;
thrust::copy(result.begin(), result.end(), std::ostream_iterator<float>(std::cout, " "));
ufn = 2;
thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(data.begin(), result.begin())),thrust::make_zip_iterator(thrust::make_tuple(data.end(),result.end())),select_functor(ufn));
std::cout<< std::endl << "cos(x): " << std::endl;
thrust::copy(result.begin(), result.end(), std::ostream_iterator<float>(std::cout, " "));
std::cout<< std::endl;
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
__主机设备浮点f1(浮点x)
{
返回sinf(x);
}
__主机设备浮点数f2(浮点数x)
{
返回cosf(x);
}
结构选择函数
{
未签名的fn;
选择_函子(无符号_-fn):fn(_-fn){};
模板
__主机设备__
void运算符()(常量元组(&t){
如果(fn==1)推力::get(t)=f1(推力::get(t));
如果(fn==2)推力::get(t)=f2(推力::get(t));
else推力::get(t)=0;
}
};
内部主(空)
{
无符号ufn=1;
常数无符号N=8;
推力::设备_矢量数据(N),结果(N);
//初始化为某些值
推力:序列(data.begin(),data.end(),0.0f,(float)(6.283/(float)N));
std::coutHow您将如何确定在特定场景中要使用的特定“math”函数?我想您需要将函数传递(或标识)给functor,而不是反过来。我认为我可以实现所需的“math”函数作为函子,并实现一个函数,该函数为给定向量的每个元素计算此math
函数。因此,此函数是通用的,但应将math
函数(实现为函子)传递给它。您将(必须)将一个函子传递到推力::for_each
。如果要传递单个(单独)假设你想对每个元素应用相同的数学函数,那么我不知道困难是什么。如果你想为每个元素传递不同的函子,你不能这样做。但是如果你想为每个元素传递相同的函子,但是(可能)有每个元素都有不同的数学计算,这是可能的,但你必须有一些方法,一个元素一个元素地确定你想要计算的内容。我认为你的问题不清楚。谢谢@Robert。我编辑了我的帖子并插入了一些代码。我打算为每个元素传递单独的函子。你现在展示的内容并不复杂k和我一样。你只是想把一个函数指针传递给一个函子。此外,你所展示的并不是要为向量的每个元素传递一个单独的函子(或函数指针)。看起来你想应用相同的函数(例如func
)感谢你,罗伯特,你的建议非常有用!
#include <thrust/device_vector.h>
#include <thrust/sequence.h>
#include <thrust/copy.h>
#include <thrust/for_each.h>
#include <thrust/iterator/zip_iterator.h>
#include <iostream>
#include <math.h>
__host__ __device__ float f1(float x)
{
return sinf(x);
}
__host__ __device__ float f2(float x)
{
return cosf(x);
}
struct select_functor
{
unsigned fn;
select_functor(unsigned _fn) : fn(_fn) {};
template <typename Tuple>
__host__ __device__
void operator()(const Tuple &t) {
if (fn == 1) thrust::get<1>(t) = f1(thrust::get<0>(t));
else if (fn == 2) thrust::get<1>(t) = f2(thrust::get<0>(t));
else thrust::get<1>(t) = 0;
}
};
int main(void)
{
unsigned ufn = 1;
const unsigned N = 8;
thrust::device_vector<float> data(N), result(N);
// initilaize to some values
thrust::sequence(data.begin(), data.end(), 0.0f, (float)(6.283/(float)N));
std::cout<< "x: " << std::endl;
thrust::copy(data.begin(), data.end(), std::ostream_iterator<float>(std::cout, " "));
thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(data.begin(), result.begin())),thrust::make_zip_iterator(thrust::make_tuple(data.end(),result.end())),select_functor(ufn));
std::cout<< std::endl << "sin(x): " << std::endl;
thrust::copy(result.begin(), result.end(), std::ostream_iterator<float>(std::cout, " "));
ufn = 2;
thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(data.begin(), result.begin())),thrust::make_zip_iterator(thrust::make_tuple(data.end(),result.end())),select_functor(ufn));
std::cout<< std::endl << "cos(x): " << std::endl;
thrust::copy(result.begin(), result.end(), std::ostream_iterator<float>(std::cout, " "));
std::cout<< std::endl;
return 0;
}