Удобно превращаем enum в число
#опытным
В прошлом посте мы выяснили, что с С++11 можно самостоятельно указывать нижележащий тип, который и хранит все элементы enum'а.
Но вот представьте себе, что вам где-то нужно получить числовое представление одного из перечислителя. К какому типу кастовать?
Это важно, потому что scoped enum неявно не приводится к числам. Нам нужно явно указывать тип:
Если вам просто нужно вывести число в поток, то кастуйте к инту, ничего страшного не будет. Однако математические операции над полученным числом могут доставить неприятности, если тип будет не тот и будут использоваться сужающие-расширяющие преобразования.
Современные IDE-шки возможно будут вам показывать нужный тип, а возможно и нет. Если тип enum'а явно указан, то можно взять его. Но если нет, то гадать не хочется. Хочется стандартного решения.
С++11 также вводит тип шаблонный тип std::underlying_type, который предоставляет зависимый тип type, содержащий подкапотный тип enum'a:
Соответственно, для каста нужно сделать такую штуку:
Плохо, что это очень громоздкая конструкция, где к тому же типы повторяются. Поэтому в С++23 ввели хэлпер-сахарок std::to_underlying, который за нас все это делает:
Красота!
Know your type. Stay cool.
#cpp11 #cpp23
#опытным
В прошлом посте мы выяснили, что с С++11 можно самостоятельно указывать нижележащий тип, который и хранит все элементы enum'а.
Но вот представьте себе, что вам где-то нужно получить числовое представление одного из перечислителя. К какому типу кастовать?
Это важно, потому что scoped enum неявно не приводится к числам. Нам нужно явно указывать тип:
enum class ColorMask : std::uint32_t
{
red = 0xFF,
green = (red << 8),
blue = (green << 8),
alpha = (blue << 8)
};
// std::cout << ColorMask::red << std::endl; // ERROR
std::cout << static_cast<int>(ColorMask::red) << std::endl;
Если вам просто нужно вывести число в поток, то кастуйте к инту, ничего страшного не будет. Однако математические операции над полученным числом могут доставить неприятности, если тип будет не тот и будут использоваться сужающие-расширяющие преобразования.
Современные IDE-шки возможно будут вам показывать нужный тип, а возможно и нет. Если тип enum'а явно указан, то можно взять его. Но если нет, то гадать не хочется. Хочется стандартного решения.
С++11 также вводит тип шаблонный тип std::underlying_type, который предоставляет зависимый тип type, содержащий подкапотный тип enum'a:
enum e1 {};
enum class e2 {};
enum class e3 : unsigned {};
enum class e4 : int {};
constexpr bool e1_t = std::is_same_v<std::underlying_type_t<e1>, int>;
constexpr bool e2_t = std::is_same_v<std::underlying_type_t<e2>, int>;
constexpr bool e3_t = std::is_same_v<std::underlying_type_t<e3>, int>;
constexpr bool e4_t = std::is_same_v<std::underlying_type_t<e4>, int>;
std::cout
<< "underlying type for 'e1' is " << (e1_t ? "int" : "non-int") << '\n'
<< "underlying type for 'e2' is " << (e2_t ? "int" : "non-int") << '\n'
<< "underlying type for 'e3' is " << (e3_t ? "int" : "non-int") << '\n'
<< "underlying type for 'e4' is " << (e4_t ? "int" : "non-int") << '\n';
// OUTPUT
// underlying type for 'e1' is non-int
// underlying type for 'e2' is int
// underlying type for 'e3' is non-int
// underlying type for 'e4' is intСоответственно, для каста нужно сделать такую штуку:
auto num = static_cast<std::underlying_type_t<ColorMask>>(ColorMask::red);
Плохо, что это очень громоздкая конструкция, где к тому же типы повторяются. Поэтому в С++23 ввели хэлпер-сахарок std::to_underlying, который за нас все это делает:
auto num = std::to_underlying(ColorMask::red);
Красота!
Know your type. Stay cool.
#cpp11 #cpp23
👍19🔥14❤7🥱1