diff --git a/include/fmt/base.h b/include/fmt/base.h index 96a2e17e..0c460624 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -1155,27 +1155,19 @@ template struct arg_mapper { static auto map(double) -> double; static auto map(long double) -> long double; - FMT_MAP_API auto map(Char* x) -> const Char* { return x; } - FMT_MAP_API auto map(const Char* x) -> const Char* { return x; } + static auto map(Char*) -> const Char*; + static auto map(const Char*) -> const Char*; template , - FMT_ENABLE_IF(std::is_same::value && - !std::is_pointer::value)> - FMT_MAP_API auto map(const T& x) -> basic_string_view { - return to_string_view(x); - } - template , - FMT_ENABLE_IF(!std::is_same::value && - !std::is_pointer::value)> - FMT_MAP_API auto map(const T&) -> unformattable_char { - return {}; - } + FMT_ENABLE_IF(!std::is_pointer::value)> + static auto map(const T&) + -> conditional_t::value, basic_string_view, + unformattable_char>; static auto map(void*) -> const void*; static auto map(const void*) -> const void*; static auto map(volatile void*) -> const void*; static auto map(const volatile void*) -> const void*; static auto map(std::nullptr_t) -> const void*; - template ::value || std::is_member_pointer::value)> static auto map(const T&) -> unformattable_pointer; @@ -2093,17 +2085,19 @@ template struct string_value { auto str() const -> basic_string_view { return {data, size}; } }; -template struct named_arg_value { - const named_arg_info* data; - size_t size; -}; - template struct custom_value { using char_type = typename Context::char_type; void* value; void (*format)(void* arg, parse_context& parse_ctx, Context& ctx); }; +template struct named_arg_value { + const named_arg_info* data; + size_t size; +}; + +struct custom_tag {}; + #if !FMT_BUILTIN_TYPES # define FMT_BUILTIN , monostate #else @@ -2136,9 +2130,9 @@ template class value { constexpr FMT_INLINE value() : no_value() {} constexpr FMT_INLINE value(signed char x) : int_value(x) {} - constexpr FMT_INLINE value(unsigned char x) : uint_value(x) {} + constexpr FMT_INLINE value(unsigned char x FMT_BUILTIN) : uint_value(x) {} constexpr FMT_INLINE value(signed short x) : int_value(x) {} - constexpr FMT_INLINE value(unsigned short x) : uint_value(x) {} + constexpr FMT_INLINE value(unsigned short x FMT_BUILTIN) : uint_value(x) {} constexpr FMT_INLINE value(int x) : int_value(x) {} constexpr FMT_INLINE value(unsigned x FMT_BUILTIN) : uint_value(x) {} FMT_CONSTEXPR FMT_INLINE value(long x FMT_BUILTIN) : value(long_type(x)) {} @@ -2179,9 +2173,14 @@ template class value { string.data = x; if (is_constant_evaluated()) string.size = 0; } - FMT_CONSTEXPR FMT_INLINE value(basic_string_view x FMT_BUILTIN) { - string.data = x.data(); - string.size = x.size(); + template , + FMT_ENABLE_IF(!std::is_pointer::value)> + FMT_CONSTEXPR value(const T& x FMT_BUILTIN) { + static_assert(std::is_same::value, + "mixing character types is disallowed"); + auto sv = to_string_view(x); + string.data = sv.data(); + string.size = sv.size(); } FMT_INLINE value(void* x FMT_BUILTIN) : pointer(x) {} FMT_INLINE value(const void* x FMT_BUILTIN) : pointer(x) {} @@ -2198,6 +2197,9 @@ template class value { "formatting of non-void pointers is disallowed"); } + template ::value)> + FMT_CONSTEXPR value(const T (&x)[N]) : value(x, custom_tag()) {} + template ::value)> value(const T& x) : value(format_as(x)) {} @@ -2210,20 +2212,17 @@ template class value { !std::is_pointer::value && !is_named_arg::value && !use_format_as::value>; - // We can't use mapped_t because of a bug in MSVC 2017. - template < - typename T, - typename M = decltype(arg_mapper::map(std::declval())), - FMT_ENABLE_IF(!std::is_same::value && mappable::value)> - FMT_CONSTEXPR20 FMT_INLINE value(T&& x) { - *this = arg_mapper::map(x); - } - template < typename T, typename M = decltype(arg_mapper::map(std::declval())), FMT_ENABLE_IF(std::is_same::value&& mappable::value)> - FMT_CONSTEXPR20 FMT_INLINE value(T&& x) { + FMT_CONSTEXPR20 FMT_INLINE value(T&& x) : value(x, custom_tag()) {} + + FMT_ALWAYS_INLINE value(const named_arg_info* args, size_t size) + : named_args{args, size} {} + + private: + template FMT_CONSTEXPR value(const T& x, custom_tag) { // Formatting of arbitrary pointers is disallowed. If you want to format a // pointer cast it to `void*` or `const void*`. In particular, this forbids // formatting of `[const] volatile char*` printed as bool by iostreams. @@ -2249,6 +2248,7 @@ template class value { "cannot format an argument; to make type T formattable provide a " "formatter specialization: https://fmt.dev/latest/api.html#udt"); + custom.value = nullptr; if (!is_constant_evaluated()) custom.value = const_cast(&reinterpret_cast(x)); @@ -2258,10 +2258,7 @@ template class value { custom.format = format_custom>; } - FMT_ALWAYS_INLINE value(const named_arg_info* args, size_t size) - : named_args{args, size} {} - private: // Formats an argument of a custom type, such as a user-defined class. template static void format_custom(void* arg, parse_context& parse_ctx,