diff --git a/include/iris/enum/enum.hpp b/include/iris/enum/enum.hpp index 60dd449..9272d38 100644 --- a/include/iris/enum/enum.hpp +++ b/include/iris/enum/enum.hpp @@ -12,7 +12,6 @@ #include #include #include -#include #ifndef NDEBUG #include @@ -29,6 +28,8 @@ struct enum_traits_not_defined {}; } // detail +// May only be specialized for program-defined enumeration types; +// otherwise, the program invokes UB when the type is formatted. template struct enum_traits : detail::enum_traits_not_defined {}; @@ -231,6 +232,14 @@ struct each_bit_fn } }; +template +constexpr bool to_string_formattable = requires(T const& val) { + { to_string(val) } -> std::formattable; +}; + +template +using to_string_t = std::remove_cvref_t()))>; + } // detail inline constexpr detail::each_bit_fn each_bit{}; @@ -238,32 +247,29 @@ inline constexpr detail::each_bit_fn each_bit{}; } // iris template - requires requires(EnumT const& val) { - { to_string(val) } -> std::formattable; - } -struct std::formatter : std::formatter, CharT> + requires iris::detail::to_string_formattable +struct std::formatter : std::formatter, CharT> { - using base_formatter = std::formatter, CharT>; + using base_formatter = std::formatter, CharT>; template - constexpr auto parse(Context& ctx) + auto format(EnumT const& val, Context& ctx) const { - if (ctx.begin() == ctx.end()) return ctx.end(); - has_format_spec_ = true; - return base_formatter::parse(ctx); + return base_formatter::format(to_string(val), ctx); } +}; + +template + requires (!iris::detail::to_string_formattable) +struct std::formatter : std::formatter, CharT> +{ + using base_formatter = std::formatter, CharT>; template auto format(EnumT const& val, Context& ctx) const { - if (has_format_spec_) { - return base_formatter::format(std::to_underlying(val), ctx); - } - return format_to(ctx.out(), "{}", to_string(val)); + return base_formatter::format(std::to_underlying(val), ctx); } - -private: - bool has_format_spec_ = false; }; #endif