在 friend sub class 中使用 base 的私有方法——NVCC 中的编译器错误?

using private method from base in friend sub class -- compiler bug in NVCC?

在尝试使用英特尔线程构建模块编译一些 CUDA 代码时,我发现了我认为是 nvcc 中的错误。以下最小示例使用 g++ 5.4:

编译良好
class Sub;
class Other;

namespace internal {
  class Base
  {
  private:
    friend class ::Sub;

    static void foo(::Sub& b);
    static void foo(::Other& c);
  };
}

class Sub : private internal::Base
{
public:
  using internal::Base::foo;
};

void internal::Base::foo(Sub& b)
{
}

int main(int argc, char *argv[])
{
  Sub *b;
  b->foo(*b);
  // Sub::foo(*b);

  return 0;
}

但是如果我用 nvcc 8.0 结合相同的主机编译器编译它,使用

nvcc -x cu -arch=sm_35 -c minimal.cc

我收到以下有趣的错误:

../minimal.cc: In function ‘int main(int, char**)’:
../minimal.cc:28:21: error: ‘internal::Base’ is an inaccessible base of ‘Sub’

如果将 Base 移出 internal 命名空间并移至全局命名空间,则会出现更具描述性的错误:

../minimal.cc: In function ‘int main(int, char**)’:
../minimal.cc:6:12: error: ‘class Base Base::Base’ is inaccessible
   class Base
            ^
../minimal.cc:32:5: error: within this context
   b->foo(*b);
     ^
../minimal.cc:32:11: error: ‘Base’ is an inaccessible base of ‘Sub’
   b->foo(*b);

很明显,这似乎是由于使用指针调用静态方法的方式有点不标准,如果该行被注释掉的行替换,它编译得很好。

有人可以确认这是有效的 C++ 并因此是 nvcc 中的错误,还是 g++ 不知何故仍然乐于接受的无效 C++?

我对此进行了更多研究,发现它确实是 nvcc 编译阶段之一的问题。使用 --save-temps,并查看生成的 .cu.cpp.ii 文件,结果发现这一行

b->foo(*b);

被以下内容取代

(b->internal::Base::foo(*b));

这不会用 g++ 编译,从那时起 fooSub 中导出为 public 的事实就丢失了。毕竟,这试图从 class 所在的 private 基址显式访问它。使用其他类型的调用 (Sub::foo) 不会导致生成任何额外代码。

我断定这是 nvcc 中的错误。有趣的是,如果未在 Base.

中声明第二个重载 void foo(::Other &c),则此替换 不会 发生