Одинаковые члены в ограниченном и неограниченном перечислениях
enum UnscopedColor { red, green, blue };
enum class ScopedColor { red, green, blue };
int main() {
using enum ScopedColor;
}
Какой из енумов будет использоваться и почему так? Как использовать определённый?
Ответы (2 шт):
В данном случае будет использоваться enum class ScopedColor, потому что он объявлен с ключевым словом class, что означает, что имена перечислений будут принадлежать области видимости этого перечисления.
Как известно,
enum UnscopedColor { red, green, blue };
не только определяет тип UnscopedColor, но и добавляет три идентификатора red, green и blue в глобальную область видимости.
Это означает, что в коде мы можем написать red и ожидать, что получим значение именно идентификатора red из перечисления UnscopedColor (т.е. 0). Правда ровно до тех пор, пока кто-нибудь не добавит в локальную область видимости новый идентификатор red, который перекроет red из глобальной области видимости. Есть много способов это сделать.
Например просто создать переменную с именем red:
#include <iostream>
enum UnscopedColor { red, green, blue };
int main() {
std::cout << red << std::endl; // это red = 0 из UnscopedColor
auto red = 42;
std::cout << red << std::endl; // а это наша новая локальная переменная red = 42
}
Или вытащить идентификатор red из каких-то глубин:
#include <iostream>
enum UnscopedColor { red, green, blue };
namespace A {
namespace B {
constexpr const char red[] = "red";
}
}
int main() {
std::cout << red << std::endl; // это red = 0 из UnscopedColor
using A::B::red;
std::cout << red << std::endl; // угадай кто здесь
}
В целом это достаточно универсальный механизм в C++ когда более новые идентификаторы вводятся в локальную область видимости и перекрывают старые (пока область видимости не закончится).
Тем не менее есть способ (не всегда, но есть) достучаться да скрытых идентификаторов. Например тех, которые объявлены в глобальной области видимости. Достаточно использовать префикс ::. Т.е. в наших примерах мы можем писать ::red и быть уверенными, что это будет именно идентификатор из UnscopedColor, а не откуда-то еще.
Возвращаясь к оригинальному коду,
enum UnscopedColor { red, green, blue };
enum class ScopedColor { red, green, blue };
int main() {
using enum ScopedColor;
}
думаю уже стало понятно какой enum "будет использоваться". Хотя это не совсем корректный вопрос. Т.к. using enum ничего не делает с самим типом ScopedColor, а только вносит имена red, green и blue типа ScopedColor в локальную область видимости (и естественно перекрывает старые идентификаторы из UnscopedColor). И если бы в ScopedColor отсутствовал blue, то в локальной области видимости мы бы получили прекрасный микс: red и green были бы типа ScopedColor, а blue принадлежал бы UnscopedColor. Ну лучше так не делать разумеется.