Ошибка VS2015 Update 1 или плохой C++: почему класс друга не может получить доступ к защищенному деструктору своего друга?

Следующее, по-видимому, является шаблоном, используемым ZeroC ICE в коде, который он автоматически генерирует, что, как мне кажется, является способом, которым они создали синглтоны (не знаю, почему) для многих выпусков их инструмента сейчас. У различных компиляторов с этим проблем нет, пока сегодня я не обнаружил, что Visual Studio 2015 Update 1 (версия VS 14.0.24720.00, версия VC++ 19.00.23506) выдает ошибку. До обновления 1 в VS2015 тоже не было с этим проблем. Я не уверен, является ли это ошибкой (регрессией?) в компиляторе С++ VS2015 с обновлением 1 или плохим (не соответствующим стандартам) кодом С++, который другие компиляторы пропускают.

Вот пример шаблона кода:

class Foo {
protected:
    virtual ~Foo() {}

    friend class Foo_init;
};

class Foo_init {
public:
    Foo init;
};

static Foo_init staticFooInit;

VS2015 Update 1 выдает следующие ошибки:

example.cpp(13): error C2248: 'Foo::~Foo': cannot access protected member declared in class 'Foo'
example.cpp(3): note: see declaration of 'Foo::~Foo'
example.cpp(1): note: see declaration of 'Foo'

Я нашел один (пока без ответа) Сообщение на форуме ZeroC ICE , похоже, связано с этим, но в остальном я не нашел в своем поиске в Google ничего, что убедило бы меня, является ли это проблемой компилятора или плохим кодом. Я признаю, что не очень хорошо знаю ZeroC ICE, и при этом я не использую дружественные классы C++ достаточно, чтобы иметь глубокое понимание того, что вы можете и не можете делать с ними. Я надеюсь, что кто-то более знающий может пролить свет на это.


person Richard Walters    schedule 19.12.2015    source источник
comment
Очевидная ошибка [компилятора] очевидна.   -  person T.C.    schedule 20.12.2015
comment
Если это действительно ошибка компилятора, я отправил отчет об ошибке в Microsoft здесь: connect. microsoft.com/VisualStudio/feedback/details/2148128   -  person Richard Walters    schedule 20.12.2015
comment
Честно говоря, все еще кажется неправильным вызывать защищенный деструктор для друга, даже если это законно.   -  person David Hoelzer    schedule 20.12.2015


Ответы (2)


Я не уверен на 100% в вашей точной проблеме, но это напоминает мне о проблеме, с которой я столкнулся некоторое время назад, когда объявленные вперед классы имели бы неожиданную область действия. эта страница класс cppreference выделяет правила, согласно которым класс, объявленный заранее, имеет самый локальный охват. Впрочем, ваш пример на моем VS2015u3 тоже не подводит.

Я думаю, что исправление, вероятно, состоит в том, чтобы заранее объявить класс, который является другом, перед классом, чтобы он имел четко определенную область.

Когда у вас есть класс, такой как

class Example {
     int someFunction( class SomeOtherClass & param );
};

Компилятор обрабатывает объявление SomeOtherClass, которое находится в локальной области видимости.

Это означает, что

class Example {
     int someFunction( class SomeOtherClass & param );
};

class SomeOtherClass {
          ...
};

Объявляет три класса Example Example::SomeOtherClass и SomeOtherClass

Изменение вашего примера на

class Foo_init;

class Foo {
  protected:
    virtual ~Foo() {}

    friend Foo_init;
 };

class Foo_init {
  public:
    Foo init;
 };

 static Foo_init staticFooInit;

Должно сработать

person mksteve    schedule 13.05.2018
comment
Я думаю, у вас есть это! Я не рассматривал область видимости раньше. - person Richard Walters; 14.05.2018

Вы использовали идентификатор, начинающийся со знака подчеркивания, а затем с заглавной буквы. Эти имена зарезервированы для реализации, и их использование в пользовательском коде является поведением undefined.

person Puppy    schedule 19.12.2015
comment
Достаточно справедливо, я отредактирую свой вопрос, чтобы исправить это. Я не думаю, что это имеет значение для моего первоначального вопроса. - person Richard Walters; 20.12.2015
comment
Кроме того, ZeroC ICE делает то же самое. :) - person Richard Walters; 20.12.2015