Использовать класс и перечисление с таким же именем?
У меня есть класс и значение перечисления, которые имеют одинаковое имя. Внутри класса я хочу использовать перечисление, которое дает ошибку. Есть ли способ использовать перечисление без переименования или перемещение в другое пространство имен?
Пример:
namespace foo {
enum bar {
BAD
};
class BAD {
void worse () {
bar b = BAD; // error
}
};
};
Ответы
Ответ 1
Это одна из тех сложных задач, как выполняется поиск имени.
В С++ есть две области идентификаторов: одна для типов классов и области общего идентификатора. Значение перечисления 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
, рассмотрите возможность использования охватывающего пространства имен или класса для класса или перечисления (предпочитайте перечисление там).
Ответ 2
bar b = foo::BAD;
или если вы находитесь в глобальном пространстве имен
bar b = ::BAD;
но это перегрузка имени - это не то, что я бы рекомендовал. С++ 0X позволит
bar b = bar::BAD;
что является лучшим решением, если допустима зависимость от С++ 0X.
Как и было обещано, объяснение
9,1/2
Если имя класса объявляется в области, где также объявлен объект, функция или перечислитель с таким же именем, то обе декларации находятся в области видимости, класс может быть отнесен только с использованием специфицированного спецификатора типа ( 3.4.4)
Разработанный тип-спецификатор представляет собой форму
class BAD b;
Это для совместимости с C, где имена тегов находятся в другом пространстве имен и должны быть [i] typedef [/i] ed, если вы хотите использовать их без специфицированного спецификатора типа. (Известный пример с функцией - это stat stat и stat stat в Unix).
Это объясняет, почему возможна перегрузка имени для обозначения класса и перечислителя. Причина, по которой BAD обозначает класс здесь, заключается в том, что имя класса также определено в области видимости класса, а в определении функции-члена поиск по масштабам выполняется следующим образом: - область функций-членов - класс - пространство имен, содержащее определение класса
BAD находится в области класса, поэтому пространство имен foo никогда не выполняется.
Ответ 3
Нет, нет способа сделать это. Вы должны использовать действительный идентификатор. Действительный идентификатор означает, что вы должны иметь возможность идентифицировать.:)
Ответ 4
Это работает в VS2008, но дает предупреждение:
bar b = bar::BAD;
Не то, что я могу порекомендовать.
Вы должны поместить перечисление в другое пространство имен внутри foo
и квалифицировать как bar
, так и BAD
с новым пространством имен.