использовать class и enum с тем же именем? - PullRequest
11 голосов
/ 12 февраля 2010

У меня есть класс и значение enum с одинаковыми именами. Внутри класса я хочу использовать enum, который выдает ошибку. Есть ли способ использовать enum без переименования или перемещения в другое пространство имен?

Пример:

namespace foo {
    enum bar {
        BAD
    };

    class BAD {
        void worse () {
            bar b = BAD; // error
        }
    };
};

Ответы [ 4 ]

9 голосов
/ 12 февраля 2010

Это одна из тех хитрых частей, как выполняется поиск имени.

В C ++ существует две области идентификаторов, одна для типов классов и общая область идентификаторов. Значение перечисления BAD находится в области общих идентификаторов, в то время как тип класса BAR находится в области идентификаторов классов. По этой причине вам разрешено иметь как перечислимое значение, так и класс с одинаковым именем: оба имени не конфликтуют.

Внутри класса BAD правила поиска идентификаторов найдут класс BAD до того, как он найдет перечисление, и, следовательно, ошибку. Теперь, если вы полностью определите идентификатор, тогда поиск имени сначала проверит область глобального идентификатора и сопоставит значение перечисления. С другой стороны, вам нужно будет добавить ключевое слово struct или class, чтобы объявить переменные типа BAD.

namespace foo {
   enum bad { BAD; };
   class BAD {
      void worse() { bad b = ::foo::BAD; } // fully qualified will match the enum
   };
}
int main() {
   // foo::BAD b;    // error, foo::BAD is an enum, not a type
   class foo::BAD b; // correct
}

Теперь я бы посоветовал против этого использования. Как правило, не рекомендуется повторно использовать такой идентификатор. Код будет более сложным и, вероятно, вводящим в заблуждение для случайного читателя (один и тот же неквалифицированный идентификатор относится к разным вещам при использовании в разных контекстах). Если имена должны быть BAD, рассмотрите возможность использования вмещающего пространства имен или класса либо для класса, либо для перечисления (предпочитайте перечисление там).

5 голосов
/ 12 февраля 2010
 bar b = foo::BAD;

или если вы находитесь в глобальном пространстве имен

 bar b = ::BAD;

но эту перегрузку имен я бы не рекомендовал. C ++ 0X позволит

 bar b = bar::BAD;

, что является лучшим решением, если зависимость от C ++ 0X является приемлемой.

Как и обещал, объяснение

9,1 / 2

Если имя класса объявлено в области видимости, где объект, функция или перечислитель с тем же именем также объявлены, то оба объявления находятся в области видимости, на класс можно ссылаться только с использованием подробно-развитого типа. -спецификатор (3.4.4)

Спецификатор уточненного типа - это форма

class BAD b;

Это для совместимости с C, где имена тегов находятся в другом пространстве имен и должны быть [i] typedef [/ i] ed, если вы хотите использовать их без подробного спецификатора типа. (Хорошо известный пример с функцией - это struct stat и функция stat в Unix).

Это объясняет, почему возможна перегрузка имени для обозначения класса и перечислителя. Причина, по которой BAD обозначает класс здесь, заключается в том, что имя класса также определено в области видимости класса, а в определении функции-члена область поиска находится в следующем порядке: - область действия функции-члена - область применения класса - пространство имен, содержащее определение класса

BAD находится в области видимости класса, поэтому пространство имен foo никогда не ищется.

0 голосов
/ 12 февраля 2010

Это работает в VS2008, но выдает предупреждение:

bar b = bar::BAD;

Это не то, что я могу порекомендовать.

Вы должны поместить enum в другое пространство имен внутри foo и квалифицировать bar и BAD с новым пространством имен.

0 голосов
/ 12 февраля 2010

Нет, нет способа сделать это. Вы должны использовать действительный идентификатор. Действительный идентификатор означает, что вы должны иметь возможность идентифицировать с ним. :)

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