Ошибочный частный недоступный базовый класс?

Компиляция этого кода с помощью g ++ 4.2.1:

struct S { };
template<typename T> struct ST { };

template<typename BaseType>
class ref_count : private BaseType { };

template<typename RefCountType>
class rep_base : public RefCountType { };

class wrap_rep : public rep_base<ref_count<S> > {
  typedef rep_base<ref_count<S> > base_type;      // line 11
};

Я добираюсь:

bug.cpp:1: error: ‘struct S’ is inaccessible
bug.cpp:11: error: within this context

Однако, если я изменяюсь wrap_rep класс для использования ST:

class wrap_rep : public rep_base<ref_count< ST<int> > > {
  typedef rep_base<ref_count< ST<int> > > base_type;
};

это компилирует прекрасный. С другой стороны, если я изменяю исходный код на:

class wrap_rep : public rep_base<ref_count<S> > {
  typedef rep_base<ref_count< ::S > > base_type;  // now using ::
};

это также компилирует прекрасный. Мне исходный код кажется прекрасным как есть. Действительно ли это - g ++ ошибка? В противном случае затем, почему делает использование шаблонной работы? И, для другого случая, почему ::S необходимо?

7
задан curiousguy 18 July 2012 в 06:25
поделиться

3 ответа

Оба этих кода недействительны (действителен только последний), но ваш компилятор (который не соответствует) диагностирует только одно. Как говорится в другом ответе, здесь используется имя внедренного класса. Считается, что класс S имеет имя члена S , обозначающее тот же самый класс. Например (обратите внимание, что ключевое слово "class" перед S :: S в первом примере необходимо для принудительной ссылки на внедренное имя класса вместо конструктора по умолчанию):

class S { };

class S::S object; // creates an S object
class X : S::S::S::S { }; // derives from class S

В шаблонах классов также есть введенное имя класса. Как и имя внедренного класса, оно наследуется производным классам, и поэтому ST неправильно сформирован, потому что он использует это имя внедренного класса, которое, однако, недоступно. Если вы используете GCC меньше 4.5, это может иметь какое-то отношение к изменению , введенному в GCC4.5:

G ++ теперь реализует DR 176. Ранее G ++ не поддерживал использование injected-class-name из базовый класс шаблона в качестве имени типа, и поиск по имени нашел объявление шаблона во включающей области.Теперь поиск имени находит внедренное имя-класса, которое может использоваться либо как тип, либо как шаблон, в зависимости от того, следует ли за именем список аргументов шаблона или нет. В результате этого изменения некоторый код, который был ранее принят, может быть неправильно сформирован, потому что

  1. введенное имя-класса недоступно, потому что оно из частной базы, или
  2. Введенное-имя-класса не может быть используется в качестве аргумента для параметра шаблона шаблона.

В любом из этих случаев код можно исправить, добавив спецификатор вложенного имени для явного имени шаблона. Первый можно обойти с помощью -fno-access-control; второй отклоняется только с -pedantic.


Чтобы немного повеселиться с внедренными именами классов - обратите внимание, что внедренное имя класса не эквивалентно typedef, как можно было бы подумать вначале. Имя внедренного класса - это имя класса, но не классифицируется как имя typedef, что означает, что оно может быть скрыто по именам функций, объектов или перечислителей:

// valid, the data-member hides the injected class name
struct S { int S; };

Чтобы сослаться на имя внедренного класса, вы можете сказать class S :: S (аналогично, в списке базовых классов имена, не являющиеся типами, игнорируются, поэтому вам не нужны особые меры предосторожности), но простой поиск по S :: S будет ссылаться на элемент данных.

7
ответ дан 7 December 2019 в 01:15
поделиться

Ваша структура S является базовым классом wrap_rep, что означает, что она вводится в wrap_rep, как если бы там был анонимный typedef.

Использование оператора :: перед S в вашем typedef скажет вашему компилятору использовать не S, от которого вы наследуете, а S в глобальном пространстве имен.

См. эту ссылку.

3
ответ дан 7 December 2019 в 01:15
поделиться

Исходный код отлично скомпилирован в обновлении Sun WorkShop 6 2 Компиляторы C ++ ». Это единственное, к чему у меня есть доступ в моем офисе. Можно попробовать любой другой компилятор, который у вас есть.

0
ответ дан 7 December 2019 в 01:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: