我有一个模板子类(模板类型名与父项或子项无关,因此不是CRTP继承案例),父项在私有访问标签部分中有一个前向声明的类。
GCC(在4.9.2和7.2上测试)编译,但clang(在5.0.0上测试)会抱怨。这是一个责备案例:
class TestClass
{
public:
// Forward-declare as public to make compile with clang
// class Thing;
private:
// GCC compiles fine with forward-declaration as private but clang gives error
class Thing;
friend class Thing;
void NotifyOfThing();
};
class TestClass::Thing
{
public:
static void NotifyOfThing() {}
};
template <typename Unrelated>
class ThingImpl final : public Unrelated
{
private:
void handleThing()
{
TestClass::Thing::NotifyOfThing();
}
};
int main() {
ThingImpl<TestClass> implementation;
}
Clang抛出错误:
25 : <source>:25:20: error: 'Thing' is a private member of 'TestClass'
TestClass::Thing::NotifyOfThing();
^
8 : <source>:8:11: note: declared private here
class Thing;
^
1 error generated.
Compiler exited with result code 1
然而,GCC接受了这一点。
现在,如果我删除模板声明,并使ThingImpl
成为非模板类,那么GCC也会对Thing
为私有提出同样的抱怨。
有人可以解释为什么会出现这种情况,哪一个更符合C ++标准?或者标准没有明确涵盖这一点?
答案 0 :(得分:4)
gcc在模板访问检查时有很多错误。见this meta-bug。您所拥有的情况完全符合41437:
class A { struct B { B(); }; };
template<typename T> void f() { A::B b; }
void g() { f<int>(); } // gcc says this is okay
clang是正确的,代码显然是不正确的。 Thing
是TestCalss
的私有类,而ThingImpl
不是TestClass
的朋友,因此ThingImpl
尝试访问TestClass::Thing
应该是访问违规。