mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 02:37:36 +02:00
Improve handling of unformattable args
This commit is contained in:
@ -1123,8 +1123,14 @@ constexpr auto has_const_formatter() -> bool {
|
|||||||
return has_const_formatter_impl<Char>(static_cast<T*>(nullptr));
|
return has_const_formatter_impl<Char>(static_cast<T*>(nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maps formatting argument types to a smaller set. Returns void on
|
template <typename T, typename Char, typename U = remove_const_t<T>>
|
||||||
// errors to be SFINAE-friendly.
|
struct formattable
|
||||||
|
: bool_constant<has_const_formatter<U, Char>() ||
|
||||||
|
(std::is_constructible<formatter<U, Char>>::value &&
|
||||||
|
!std::is_const<T>::value)> {};
|
||||||
|
|
||||||
|
// Maps formatting argument types to natively supported types or user-defined
|
||||||
|
// types with formatters. Returns void on errors to be SFINAE-friendly.
|
||||||
template <typename Char> struct type_mapper {
|
template <typename Char> struct type_mapper {
|
||||||
static auto map(signed char) -> int;
|
static auto map(signed char) -> int;
|
||||||
static auto map(unsigned char) -> unsigned;
|
static auto map(unsigned char) -> unsigned;
|
||||||
@ -1176,14 +1182,8 @@ template <typename Char> struct type_mapper {
|
|||||||
template <typename T, FMT_ENABLE_IF(use_format_as<T>::value)>
|
template <typename T, FMT_ENABLE_IF(use_format_as<T>::value)>
|
||||||
static auto map(const T& x) -> decltype(map(format_as(x)));
|
static auto map(const T& x) -> decltype(map(format_as(x)));
|
||||||
|
|
||||||
template <typename T, typename U = remove_const_t<T>>
|
|
||||||
struct formattable
|
|
||||||
: bool_constant<has_const_formatter<U, Char>() ||
|
|
||||||
(std::is_constructible<formatter<U, Char>>::value &&
|
|
||||||
!std::is_const<T>::value)> {};
|
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(use_formatter<remove_const_t<T>>::value)>
|
template <typename T, FMT_ENABLE_IF(use_formatter<remove_const_t<T>>::value)>
|
||||||
static auto map(T&) -> conditional_t<formattable<T>::value, T&, void>;
|
static auto map(T&) -> conditional_t<formattable<T, Char>::value, T&, void>;
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
|
template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
|
||||||
static auto map(const T& named_arg) -> decltype(map(named_arg.value));
|
static auto map(const T& named_arg) -> decltype(map(named_arg.value));
|
||||||
@ -2192,23 +2192,15 @@ template <typename Context> class value {
|
|||||||
: named_args{args, size} {}
|
: named_args{args, size} {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename T> FMT_CONSTEXPR value(const T& x, custom_tag) {
|
template <typename T, FMT_ENABLE_IF(formattable<T, char_type>::value)>
|
||||||
|
FMT_CONSTEXPR value(const T& x, custom_tag) {
|
||||||
using value_type = remove_cvref_t<T>;
|
using value_type = remove_cvref_t<T>;
|
||||||
enum { formattable = !std::is_same<T, void>::value };
|
|
||||||
|
|
||||||
#if defined(__cpp_if_constexpr)
|
#if defined(__cpp_if_constexpr)
|
||||||
if constexpr (!formattable) type_is_unformattable_for<T, char_type> _;
|
|
||||||
|
|
||||||
// T may overload operator& e.g. std::vector<bool>::reference in libc++.
|
// T may overload operator& e.g. std::vector<bool>::reference in libc++.
|
||||||
if constexpr (std::is_same<decltype(&x), remove_reference_t<T>*>::value)
|
if constexpr (std::is_same<decltype(&x), remove_reference_t<T>*>::value)
|
||||||
custom.value = const_cast<value_type*>(&x);
|
custom.value = const_cast<value_type*>(&x);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static_assert(
|
|
||||||
formattable,
|
|
||||||
"cannot format an argument; to make type T formattable provide a "
|
|
||||||
"formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
|
|
||||||
|
|
||||||
custom.value = nullptr;
|
custom.value = nullptr;
|
||||||
if (!is_constant_evaluated())
|
if (!is_constant_evaluated())
|
||||||
custom.value =
|
custom.value =
|
||||||
@ -2216,6 +2208,13 @@ template <typename Context> class value {
|
|||||||
custom.format = format_custom<value_type, formatter<value_type, char_type>>;
|
custom.format = format_custom<value_type, formatter<value_type, char_type>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, FMT_ENABLE_IF(!formattable<T, char_type>::value)>
|
||||||
|
FMT_CONSTEXPR value(const T&, custom_tag) {
|
||||||
|
// Cannot format an argument; to make type T formattable provide a
|
||||||
|
// formatter<T> specialization: https://fmt.dev/latest/api.html#udt.
|
||||||
|
type_is_unformattable_for<T, char_type> _;
|
||||||
|
}
|
||||||
|
|
||||||
// Formats an argument of a custom type, such as a user-defined class.
|
// Formats an argument of a custom type, such as a user-defined class.
|
||||||
template <typename T, typename Formatter>
|
template <typename T, typename Formatter>
|
||||||
static void format_custom(void* arg, parse_context<char_type>& parse_ctx,
|
static void format_custom(void* arg, parse_context<char_type>& parse_ctx,
|
||||||
|
@ -779,7 +779,7 @@ using is_integer =
|
|||||||
#if FMT_USE_FLOAT128
|
#if FMT_USE_FLOAT128
|
||||||
using float128 = __float128;
|
using float128 = __float128;
|
||||||
#else
|
#else
|
||||||
using float128 = void;
|
struct float128 {};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename T> using is_float128 = std::is_same<T, float128>;
|
template <typename T> using is_float128 = std::is_same<T, float128>;
|
||||||
|
Reference in New Issue
Block a user