哪种编译器是正确的 - 或者这是标准中的缺陷?
GCC编译以下代码,但clang抱怨:
<source>:20:7: error: 'Impl' is a protected member of 'A'
码:
template<typename T>
struct WrapperBuilder;
template <typename T>
struct LetMeIn : public T {
friend struct WrapperBuilder<T>;
};
class A {
protected:
struct Impl;
};
// without this line, gcc complains too (but I think I understand why)
extern template struct LetMeIn<A>;
template<>
struct WrapperBuilder<A> {
A::Impl * i; // Clang doesn't like this line
};
谢谢。
此外,任何人都知道clang的解决方法,不涉及更改A
?
铿锵是对的。请注意,gcc具有带模板访问权限的many bugs。
Impl
是A
的受保护成员,WrapperBuilder<A>
既不源于A
,也不是friend
的A
。
LetMeIn
没有以相关的方式赐予友谊。明确的模板实例化使WrapperBuilder<A>
成为friend
的LetMeIn<A>
,但友谊不是传递性的 - 这不会使它成为friend
的A
。
LetMinIn<A>::Impl
工作...但非常间接。如果你想要你可以更直接地做到:
struct LetMeIn : A {
using Impl = A::Impl;
};
现在它是公开的。
Clang就在这里。当你这样做
template <typename T>
struct LetMeIn : public T {
friend struct WrapperBuilder<T>;
};
WrapperBuilder<T>
成为LetMeIn<T>
的朋友。这意味着WrapperBuilder<T>
可以访问LetMeIn<T>
中的任何内容。由于LetMeIn<T>
继承自T
,这也意味着WrapperBuilder<T>
可以访问T
可以访问的LetMeIn<T>
的LetMeIn<T>
部分。这并不意味着WrapperBuilder<T>
成为T
的朋友
为了表明这一点
template<>
struct WrapperBuilder<A> {
LetMeIn<A>::Impl* foo;
};
由于WrapperBuilder<A>
可以访问LetMeIn<A>
成员,因此可以在clang和gcc中编译。