diff --git a/include/magic_enum.hpp b/include/magic_enum.hpp index 914b46f..8539b69 100644 --- a/include/magic_enum.hpp +++ b/include/magic_enum.hpp @@ -119,9 +119,9 @@ template (name.front() >= 'A' && name.front() <= 'Z') || (name.front() == '_'))) { return name; - } else { - return {}; // Invalid name. } + + return {}; // Invalid name. } template @@ -153,11 +153,11 @@ template static_assert(std::is_enum_v, "magic_enum::detail::name_impl requires enum type."); constexpr auto names = strings_impl(range_impl()); - if (auto i = static_cast(value - min_impl()); i < names.size()) { + if (auto i = static_cast((value - min_impl())); i < names.size()) { return names[i]; - } else { - return {}; // Value out of range. } + + return {}; // Value out of range. } template @@ -195,7 +195,13 @@ template } template -using enable_if_enum_t = std::enable_if_t>>; +using remove_cvref_t = std::remove_cv_t>; + +template +using enable_if_enum_t = std::enable_if_t>, remove_cvref_t>; + +template +inline constexpr bool check_enum_v = std::is_same_v, D> && std::is_enum_v; template > struct is_scoped_enum_impl : std::false_type {}; @@ -257,10 +263,9 @@ using underlying_type_t = typename underlying_type::type; // Obtains enum value from enum string name. // Returns std::optional with enum value. -template > -[[nodiscard]] constexpr std::optional> enum_cast(std::string_view value) noexcept { - using D = std::decay_t; - static_assert(std::is_enum_v, "magic_enum::enum_cast requires enum type."); +template > +[[nodiscard]] constexpr std::optional enum_cast(std::string_view value) noexcept { + static_assert(detail::check_enum_v, "magic_enum::enum_cast requires enum type."); constexpr auto values = detail::values_impl(detail::range_impl()); constexpr auto count = values.size(); constexpr auto names = detail::names_impl(std::make_index_sequence{}); @@ -276,33 +281,30 @@ template > // Obtains enum value from integer value. // Returns std::optional with enum value. -template > -[[nodiscard]] constexpr std::optional> enum_cast(std::underlying_type_t> value) noexcept { - using D = std::decay_t; - static_assert(std::is_enum_v, "magic_enum::enum_cast requires enum type."); +template > +[[nodiscard]] constexpr std::optional enum_cast(std::underlying_type_t value) noexcept { + static_assert(detail::check_enum_v, "magic_enum::enum_cast requires enum type."); if (detail::name_impl(static_cast(value)).empty()) { return std::nullopt; // Invalid value or out of range. - } else { - return static_cast(value); } + + return static_cast(value); } // Returns integer value from enum value. -template > +template > [[nodiscard]] constexpr auto enum_integer(E value) noexcept { - using D = std::decay_t; - static_assert(std::is_enum_v, "magic_enum::enum_integer requires enum type."); + static_assert(detail::check_enum_v, "magic_enum::enum_integer requires enum type."); return static_cast>(value); } // Returns enum value at specified index. // No bounds checking is performed: the behavior is undefined if index >= number of enum values. -template> +template> [[nodiscard]] constexpr auto enum_value(std::size_t index) { - using D = std::decay_t; - static_assert(std::is_enum_v, "magic_enum::enum_value requires enum type."); + static_assert(detail::check_enum_v, "magic_enum::enum_value requires enum type."); constexpr auto values = detail::values_impl(detail::range_impl()); return assert(index < values.size()), values[index]; @@ -310,50 +312,45 @@ template> // Obtains value enum sequence. // Returns std::array with enum values, sorted by enum value. -template > +template > [[nodiscard]] constexpr auto enum_values() noexcept { - using D = std::decay_t; - static_assert(std::is_enum_v, "magic_enum::enum_values requires enum type."); + static_assert(detail::check_enum_v, "magic_enum::enum_values requires enum type."); constexpr auto values = detail::values_impl(detail::range_impl()); return values; } // Returns number of enum values. -template > -[[nodiscard]] constexpr auto enum_count() noexcept { - using D = std::decay_t; - static_assert(std::is_enum_v, "magic_enum::enum_count requires enum type."); - constexpr auto count = detail::values_impl(detail::range_impl()).size(); +template > +[[nodiscard]] constexpr std::size_t enum_count() noexcept { + static_assert(detail::check_enum_v, "magic_enum::enum_count requires enum type."); + constexpr std::size_t count = detail::values_impl(detail::range_impl()).size(); return count; } // Returns string enum name from static storage enum variable. // This version is much lighter on the compile times and is not restricted to the enum_range limitation. -template > +template > [[nodiscard]] constexpr std::string_view enum_name() noexcept { - using D = std::decay_t; - static_assert(std::is_enum_v, "magic_enum::enum_name requires enum type."); + static_assert(detail::check_enum_v, "magic_enum::enum_name requires enum type."); return detail::name_impl(); } // Returns string enum name from enum value. -template > +template > [[nodiscard]] constexpr std::string_view enum_name(E value) noexcept { - using D = std::decay_t; - static_assert(std::is_enum_v, "magic_enum::enum_name requires enum type."); + static_assert(detail::check_enum_v, "magic_enum::enum_name requires enum type."); return detail::name_impl(static_cast(value)); } // Obtains string enum name sequence. // Returns std::array with string enum names, sorted by enum value. -template > +template > [[nodiscard]] constexpr auto enum_names() noexcept { - using D = std::decay_t; - static_assert(std::is_enum_v, "magic_enum::enum_names requires enum type."); + static_assert(detail::check_enum_v, "magic_enum::enum_names requires enum type."); constexpr auto count = detail::values_impl(detail::range_impl()).size(); constexpr auto names = detail::names_impl(std::make_index_sequence{}); @@ -362,10 +359,9 @@ template > // Obtains pair (value enum, string enum name) sequence. // Returns std::array with std::pair (value enum, string enum name), sorted by enum value. -template > +template > [[nodiscard]] constexpr auto enum_entries() noexcept { - using D = std::decay_t; - static_assert(std::is_enum_v, "magic_enum::enum_entries requires enum type."); + static_assert(detail::check_enum_v, "magic_enum::enum_entries requires enum type."); constexpr auto count = detail::values_impl(detail::range_impl()).size(); constexpr auto entries = detail::entries_impl(std::make_index_sequence{}); @@ -374,10 +370,9 @@ template > namespace ops { -template > +template > std::basic_ostream& operator<<(std::basic_ostream& os, E value) { - using D = std::decay_t; - static_assert(std::is_enum_v, "magic_enum::ops::operator<< requires enum type."); + static_assert(detail::check_enum_v, "magic_enum::ops::operator<< requires enum type."); if (auto name = detail::name_impl(static_cast(value)); !name.empty()) { for (auto c : name) { @@ -388,10 +383,9 @@ std::basic_ostream& operator<<(std::basic_ostream& o return os; } -template > +template > std::basic_ostream& operator<<(std::basic_ostream& os, std::optional value) { - using D = std::decay_t; - static_assert(std::is_enum_v, "magic_enum::ops::operator<< requires enum type."); + static_assert(detail::check_enum_v, "magic_enum::ops::operator<< requires enum type."); if (value.has_value()) { if (auto name = detail::name_impl(static_cast(value.value())); !name.empty()) {