CUDA C ++中的友元函数

问题描述 投票:1回答:2

我正在研究在命名空间test0中声明类A和B以及在命名空间test1中声明的类A的友元函数f的问题。函数f接收B类对象的引用作为参数。这是一个简化的例子。

namespace test0 {
    class B;
}

namespace test1 {
    void f(test0::B& b);
}

namespace test0 {
    class A {
        friend void test1::f(test0::B& b);
    };
}

该代码适用于g ++。但是nvcc给出了以下编译错误。

a.cu:11:22: error: ‘B’ has not been declared
        friend void test1::f(test0::B& b);
                    ^
a.cu:11:27: error: ‘void test1::f(int&)’ should have been declared inside ‘test1’
        friend void test1::f(test0::B& b);
                        ^

你能帮我弄清楚问题是什么吗?先感谢您。

c++ compiler-errors cuda nvcc friend-function
2个回答
1
投票

重要的是要理解nvcc不是编译器,它是编译器驱动程序,在这两种情况下,代码都是用gcc编译的,错误是gcc生成的错误。如果您将该代码放在.cc扩展文件中并通过nvcc进行编译,则不会出现错误。

但是在编译CUDA代码时(在这种情况下在.cu文件中),在代码和编译它的最终g ++传递之间有一些中间处理阶段。在幕后,正在发生的事情是CUDA C ++前端解析器将您的代码转换为:

# 1
# 2
namespace test0 { 
# 3
    class B; 
# 4
}
# 6
namespace test1 { 
# 7
    void f(test0::B & b); 
# 8
}
# 10
namespace test0 { 
# 11
    class A { 
# 12
        friend void test1::f(B & b); 
# 13
    }; 
# 14
}

将其与原始friend void test1::f(test0::B& b);进行比较,您可以看到命名空间已被cudafe ++传递剥离。我不知道为什么它被剥离了,但那是错误的根源。

如果它是您应用程序中的真正问题,我建议将此报告为NVIDIA的错误。


1
投票

经过NVIDIA开发团队的审核后,似乎可能会暴露gnu编译器中的错误。确实,nvcc工具链的前端处理创建了一个主机代码(传递给主机编译器),它删除了b类型的命名空间限定,但这应该是可以接受的,因为B已经在test0命名空间中声明了。

看来这对gnu社区有already been reported

作为支持数据点,Fedora 25上的clang ++ 3.9.1编译了由@talonmies给出的answer中报告的代码,没有错误也没有警告。在我通过Fedora25上的gnu 6.4.1进行测试时,gnu工具链仍会抛出错误。我并没有声称这是一个证明点,只是暗示gnu中的bug声称可能是正确的。我不是语言专家。此外,我不想在此就此发表争论;这不是这个问题或答案的目的。

NVIDIA开发团队已经对该问题进行了审核,并希望在未来的CUDA版本中进行修复或解决。

与此同时,建议的源级解决方法是在类B中为A使用虚拟typedef。即:

class A {
    typedef B dummy_t;
    friend void test1::f(dummy_t & b);
};

更新:

该问题应在CUDA 10.1.105(CUDA 10.1)中解决

© www.soinside.com 2019 - 2024. All rights reserved.