Ошибочный частный базовый класс недоступен? - PullRequest
7 голосов
/ 12 июля 2010

Компиляция этого кода с использованием 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 необходим?

Ответы [ 3 ]

7 голосов
/ 12 июля 2010

Оба этих кода недействительны (допустим только последний), но ваш компилятор (который не соответствует) только диагностирует один.Как говорит другой ответ, для этого используется введенное имя класса.Считается, что класс 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<int> является неправильно сформированным, поскольку использует это внедренное имя класса, которое, однако, недоступно.Если вы используете 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 будет ссылаться на член-данные,

3 голосов
/ 12 июля 2010

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

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

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

0 голосов
/ 12 июля 2010

Оригинальный код прекрасно скомпилирован в "Sun WorkShop 6 update 2 Compilers C ++". Это единственный, к которому у меня есть доступ в моем офисе. Может быть, попробуйте любой другой компилятор, который у вас есть.

...