Доступ к защищенному типу в классе через друга - gcc позволяет, clang - нет - PullRequest
0 голосов
/ 05 сентября 2018

Какой компилятор прав - или это дефект в стандарте?

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

Кроме того, кто-нибудь знает обходной путь кланга, который не включает изменение A?

Ответы [ 2 ]

0 голосов
/ 05 сентября 2018

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

};

Компилируется как в clang, так и в gcc, поскольку WrapperBuilder<A> может иметь доступ к LetMeIn<A> членам.

0 голосов
/ 05 сентября 2018

лязг прав. Обратите внимание, что у gcc есть много ошибок с проверкой доступа в шаблонах.

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

А теперь это публично.

...