通过朋友访问类中的受保护类型 - gcc允许,clang不允许

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

哪种编译器是正确的 - 或者这是标准中的缺陷?

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
};

谢谢。

https://godbolt.org/z/Qa7zZ6

此外,任何人都知道clang的解决方法,不涉及更改A

c++ gcc clang language-lawyer
2个回答
2
投票

铿锵是对的。请注意,gcc具有带模板访问权限的many bugs

ImplA的受保护成员,WrapperBuilder<A>既不源于A,也不是friendA

LetMeIn没有以相关的方式赐予友谊。明确的模板实例化使WrapperBuilder<A>成为friendLetMeIn<A>,但友谊不是传递性的 - 这不会使它成为friendA


LetMinIn<A>::Impl工作...但非常间接。如果你想要你可以更直接地做到:

struct LetMeIn : A {
    using Impl = A::Impl;
};

现在它是公开的。


1
投票

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中编译。

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