CUDA C ++中的友元函数

时间:2018-05-27 08:52:24

标签: c++ compiler-errors cuda nvcc friend-function

我正在研究在命名空间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);
                        ^
你可以帮我弄清楚问题是什么吗?提前谢谢。

2 个答案:

答案 0 :(得分: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 :(得分: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 中的错误可能可能是正确的。我不是语言专家。此外,我不想在此就此发表争论;这不是这个问题或答案的目的。

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)

中解决