C++ 具有虚拟继承的对象传递给cuda内核函数

C++ 具有虚拟继承的对象传递给cuda内核函数,c++,cuda,pass-by-value,virtual-inheritance,C++,Cuda,Pass By Value,Virtual Inheritance,我能够将普通对象作为副本传递给内核函数。但是,当我将虚拟继承添加到类层次结构时,我收到一条错误消息,指出具有用户定义的复制构造函数的类不能用作内核启动的参数。但是,我没有用户定义的复制构造函数。所以我猜这是因为虚拟继承的内部实现实现了一些不同类型的复制构造函数。有人能解释一下虚拟继承实际上是如何实现的吗?是否有任何解决方法,或者在编写cuda代码时是否绝对没有使用虚拟继承的方法 代码如下所示: class Base {...}; class ChildA: public virtual Base

我能够将普通对象作为副本传递给内核函数。但是,当我将虚拟继承添加到类层次结构时,我收到一条错误消息,指出具有用户定义的复制构造函数的类不能用作内核启动的参数。但是,我没有用户定义的复制构造函数。所以我猜这是因为虚拟继承的内部实现实现了一些不同类型的复制构造函数。有人能解释一下虚拟继承实际上是如何实现的吗?是否有任何解决方法,或者在编写cuda代码时是否绝对没有使用虚拟继承的方法

代码如下所示:

class Base {...};
class ChildA: public virtual Base {...};
class ChildB: public virtual Base {...};
class GrandChild: public ChildA, public ChildB {...};

__global__ void mykernel(Base x) {...}

int main() {
  GrandChild x;
  mykernel<<<1,1>>>(x);
  return 0;
}
类基类{…};
类ChildA:公共虚拟基{…};
类ChildB:公共虚拟基{…};
类孙子:公共ChildA,公共ChildB{…};
__全局\uuuvoid mykernel(基x){…}
int main(){
孙子x;
mykernel(x);
返回0;
}
编辑:
以下是我的猜测:我认为nvcc只允许默认的复制构造函数,因为在这种情况下,它可以简单地使用cudaMemcpyAsync将参数推送到设备内部的调用堆栈中。因此,它硬编码了编译器,这样只允许使用默认的复制构造函数,但内部具有虚拟继承的对象具有不同类型的复制构造函数,从而触发了nvcc中的错误。但是,我仍然认为NVCC可以允许它的一种简单的方式,只要NVCC支持虚拟函数和其他高级C++特性。根据@RobertCrovella提供的链接中的以下两条声明,我所做的是不允许的

  • 不允许将带有虚拟函数的类的对象作为参数传递给
    \uuuu全局\uuu
    函数
  • 不允许将从虚拟基类派生的类的对象作为参数传递给
    \uuuu全局\uuu
    函数
  • 加上提供的@Joky链接,我认为原因在于nvcc使用一个简单的内存拷贝将参数从主机内存推送到设备内存中的调用堆栈中。这就是为什么不允许使用非默认复制构造函数,因为只有默认复制构造函数与这种简单的内存复制行为一致

    我使用的解决方案是打破一个继承关系,并设置一个类型转换操作符来保留缺少的链接以进行向上转换,如下所示。这对我来说很好,因为所有这些类都只是指针的包装器,类型转换足够有效,尽管代价是有时我必须进行显式类型转换,比如下面调用
    mykernel2
    函数

    class Base {...};
    class ChildA: public Base {...};
    class ChildB: public Base {...};
    class GrandChild: public ChildA {
    public:
      operator ChildB () {...}
    };
    
    __global__ void mykernel(Base x) {...}
    __global__ void mykernel2(ChildB y) {...}
    
    int main() {
      GrandChild x;
      mykernel<<<1,1>>>(x);
      mykernel2<<<1,1>>>(ChildB(x));
      return 0;
    }
    
    类基类{…};
    类ChildA:公共基{…};
    类ChildB:公共基{…};
    孙辈阶级:公共儿童{
    公众:
    运算符ChildB(){…}
    };
    __全局\uuuvoid mykernel(基x){…}
    __全局无效mykernel2(儿童){…}
    int main(){
    孙子x;
    mykernel(x);
    mykernel2(ChildB(x));
    返回0;
    }
    
    请参见此处了解其实现方式(在gcc中);它可能会给你一个第一个想法。只要支持虚拟函数,我就看不到支持虚拟继承的技术限制的琐碎解释。您正在按值传递x。您可能对@Joky感兴趣,谢谢您的精彩参考。我现在正在阅读,过一会儿就会回来。@MadScienceDreams是的,我是通过值传递它的,其思想是我们使用对象来打包一组设备指针,并立即将它们传递给内核,而不是在内核函数中传递大量参数。