Почему количество элементов в перечислении изменяет видимость закрытого определения типа в C ++? - PullRequest
2 голосов
/ 05 июля 2010

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

Я собирался прийти сюда и спросить, почему работает следующий пример. Это демонстрировало поведение, на которое я надеялся, но я не был уверен, почему, или было ли это стандартным, или мне просто повезло с компилятором. Во всяком случае, разбирая минимальный рабочий пример для публикации здесь, я обнаружил, что он не делает то, что я думал. Так что вот оно ...

   struct Foo {
       enum BAR { A, B, C, D, E };
       private: typedef BAR BAR;
   };

   int main(int argc, char* argv[]) {
       int x = (Foo::BAR)42;
       int y = Foo::D;
  }

То, что, кажется, происходит, и что меня весьма порадовало, это то, что Foo принимает константы перечисления, после чего BAR становится приватным. Так что я не получаю ошибку на int y =, но я получаю Foo::BAR частную ошибку на int x=. Однако кажется, что это работает только с 5 или более константами в перечислении, удалите это E, и все это прекрасно скомпилируется, то есть BAR остается открытым.

Что здесь на работе? Спасибо.

(PS. Компилятор GCC 4.4.3)

Ответы [ 4 ]

6 голосов
/ 05 июля 2010

Я могу проверить ваши результаты о четырех элементах перечисления против пяти ... это похоже на неясную ошибку GCC.

Что касается «что здесь работает», то это связано с техническими особенностями между различными пространствами имен символов в C ++ (унаследованными от C). См. этот ответ для более подробной информации.

Если вы не хотите, чтобы отображался символ с именем BAR, просто опустите имя тега:

struct Foo {
    enum { A, B, C, D, E };
};

Если вы объявляете именованное общедоступное перечисление, тогда независимо от того, что вы делаете , даже если вы скрываете имя, используя typedef, посторонние могут получить доступ к перечислению, используя разработанный спецификатор типа, Попытка скрыть название символа таким способом бесполезна:

 struct Foo {
     enum BAR { A, B, C, D, E };
     private: typedef BAR BAR;
 };

 int main(int argc, char* argv[]) {
     int x = (enum Foo::BAR)42;  // works great!
     int y = Foo::D;
}

Есть ли какая-то особая причина, по которой вы хотите, чтобы константы были общедоступными, пока имя перечисления остается приватным?

2 голосов
/ 05 июля 2010

Имя typedef не должно конфликтовать с именем типа enum.Вместо этого имя typedef должно скрыть ранее объявленное имя типа enum.Поскольку имя typedef является приватным, оно должно быть недоступно извне

Foo::BAR i; // ERROR, `Foo::BAR` is private

Тем не менее, вы можете обратиться к скрытому общедоступному имени типа enum, используя подробный спецификатор типа

enum Foo::BAR i; // OK

Сами константы перечисления, конечно, общедоступны и должны оставаться доступными в вашем примере.

Поведение не должно зависеть от количества констант в перечислении.Если вы наблюдаете описанную зависимость, это может быть ошибка в компиляторе.

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

При запуске «g ++ -c file.cpp» в MacOS X 10.6.4 с G ++ 4.2.1 код компилируется без рывков с 4 и 5 элементами в перечислении. Добавление '-Wall -pedantic' вызывает только жалобы на неиспользуемые переменные x и y.

Как отмечено в комментарии (и заголовке вопроса), количество элементов в перечислении не должно влиять на поведение. Для меня такое разное поведение попахивает «ошибка» (в GCC).

Какое правильное поведение сложнее; Я не хочу занимать сильную позицию по этому поводу. В среднем я предпочитаю, чтобы 'Foo :: BAR' сначала объявлялся общедоступным, а более поздний закрытый typedef должен игнорироваться или быть ошибкой. Тем не менее, это очень далеко от окончательного взгляда на то, каким должно быть поведение - я очень не уверен.

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

Я бы не хотел говорить что-то вроде «Microsoft все правильно понял», но я не могу найти в стандарте ничего такого, что поддерживало бы такое поведение. Насколько я могу судить, имя типа Foo :: BAR всегда должно оставаться общедоступным.

Нет никаких отклонений в этом поведении от MSVC ++. Это всегда позволяет вашему примеру кода скомпилироваться без ошибок. Я перепробовал все до 26 записей в BAR.

Я бы осмелился сказать, что это ошибка в gcc.

Однако я должен согласиться с тем, что уже было сказано - я не думаю, что этот код заслуживает компиляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...