класс — C ++: странный & quot; закрытый & quot; ошибка

Я получил очень необычную ошибку от g ++, утверждая, что псевдоним типа является закрытым. После нескольких часов сокращения моего кода я пришел к следующему минимальному тестовому примеру:

template <typename Dummy>
class Test {
struct CatDog {
static void meow ()
{
CrazyHouse::TheCatDog::meow();
}

struct Dog {
static void bark ();
};
};

struct CrazyHouse {
using TheCatDog = CatDog;

static void startMadness ()
{
TheCatDog::meow();
TheCatDog::Dog::bark();
}
};

public:
static void init ()
{
CrazyHouse::startMadness();
}
};

int main ()
{
Test<void> t;
t.init();
}

Ошибка с g ++ 4.8.2:

test.cpp: In instantiation of 'static void Test<Dummy>::CatDog::meow() [with Dummy = void]':
test.cpp:19:29:   required from 'static void Test<Dummy>::CrazyHouse::startMadness() [with Dummy = void]'
test.cpp:27:34:   required from 'static void Test<Dummy>::init() [with Dummy = void]'
test.cpp:34:12:   required from here
test.cpp:15:33: error: 'using TheCatDog = struct Test<void>::CatDog' is private
using TheCatDog = CatDog;
^
test.cpp:6:41: error: within this context
CrazyHouse::TheCatDog::meow();
^

Clang 3.4 принимает тот же код. Что здесь происходит, это ошибка G ++?

Выполнение любого из следующих действий останавливает возникновение ошибки:

  • Превращение Test в класс, в отличие от класса шаблона.
  • Удаление любого из операторов в любой из функций.
  • изменения TheCatDog::Dog::bark(); в CatDog::Dog::bark();,
  • Удаление CrazyHouse класс и слияние его содержимого в Test,
  • Удаление CatDog класс, сливая его содержимое в Test и изменение TheCatDog псевдоним, чтобы указать на Test,

7

Решение

Поиск имени по идентификатору CatDog находки Test::CatDog который объявлен private, Доступ осуществляется с CrazyHouse, который не является friend из Test, Поэтому это незаконный доступ к защищенному участнику.

Как отмечает @ sj0h, в C ++ 11 ваш пример становится действительным, потому что они решили расширить доступ к телам вложенных классов таким же образом, как и функции-члены.

C ++ 98:

Члены вложенного класса не имеют специального доступа ни к членам включающего класса, ни к классам или функциям, которые предоставили дружбу включающему классу; должны соблюдаться обычные правила доступа (пункт 11).

C ++ 11:

Вложенный класс является членом, и поэтому имеет те же права доступа, что и любой другой член.

(Участники имеют право доступа private члены вмещающего класса.)

Однако это изменение, похоже, не реализовано в GCC даже в последней сборке версии 4.9. Таким образом, чтобы быть в безопасности, это не помешает добавить friend декларация. Это должно идти после определение члена:

friend struct CrazyHouse;

Обратите внимание, что это не делает то же самое, что изменение C ++ 11, потому что friendКорабль не транзитивен, тогда как доступ, предоставленный вложенным членством.

5

Другие решения

Поведение компиляторов можно считать неправильным или правильным в зависимости от того, о какой версии C ++ идет речь. Похоже, что поведение clang правильное, если мы говорим о C ++ 11, и неправильное, если мы говорим о C ++ 98.

Элемент stackoverflow Доступ к вложенным классам C ++ следует уточнить это.

-1

По вопросам рекламы [email protected]