From 8ecf90f686e1bdcc816c8cbc839be0629d3ecc1e Mon Sep 17 00:00:00 2001 From: Aamr El Kazdadi Date: Mon, 9 Dec 2019 15:23:59 +0100 Subject: [PATCH] Improve error messages --- include/fmt/core.h | 58 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index efe6c8e5..4943f7d3 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -681,6 +681,12 @@ template using has_fallback_formatter = std::is_constructible>; +// Speicifies if T has an enabled formatter or fallback_formatter specialization +template +struct has_any_formatter + : conditional_t::value, std::true_type, + has_fallback_formatter> {}; + template struct named_arg_base; template struct named_arg; @@ -794,7 +800,8 @@ template class value { } value(const void* val) : pointer(val) {} - template value(const T& val) { + template ::value)> + value(const T& val) { custom.value = &val; // Get the formatter type through the context to allow different contexts // have different extension points, e.g. `formatter` for `format` and @@ -804,6 +811,10 @@ template class value { typename Context::template formatter_type, fallback_formatter>>; } + template ::value)> + value(const T& val) { + (void)val; + } value(const named_arg_base& val) { named_arg = &val; } @@ -829,7 +840,7 @@ using long_type = conditional_t; using ulong_type = conditional_t; // Maps formatting arguments to core types. -template struct arg_mapper { +template struct arg_mapper_impl { using char_type = typename Context::char_type; FMT_CONSTEXPR int map(signed char val) { return val; } @@ -878,9 +889,7 @@ template struct arg_mapper { FMT_ENABLE_IF( std::is_constructible, T>::value && !std::is_constructible, T>::value && - !is_string::value && - !has_formatter::value && - !has_fallback_formatter::value)> + !is_string::value && !has_any_formatter::value)> FMT_CONSTEXPR basic_string_view map(const T& val) { return std_string_view(val); } @@ -905,10 +914,8 @@ template struct arg_mapper { return 0; } - template ::value && - !has_formatter::value && - !has_fallback_formatter::value)> + template ::value && + !has_any_formatter::value)> FMT_CONSTEXPR auto map(const T& val) -> decltype( map(static_cast::type>(val))) { return map(static_cast::type>(val)); @@ -917,8 +924,7 @@ template struct arg_mapper { FMT_ENABLE_IF(!is_string::value && !is_char::value && !std::is_constructible, T>::value && - (has_formatter::value || - has_fallback_formatter::value))> + has_any_formatter::value)> FMT_CONSTEXPR const T& map(const T& val) { return val; } @@ -932,6 +938,36 @@ template struct arg_mapper { } }; +template struct arg_mapper { + template struct always_true : std::true_type {}; + + // Checks if arg_mapper_impl().map(val) can be valid + template + struct is_mappable : std::false_type {}; + template + struct is_mappable< + T, enable_if_t().map( + std::declval()))>::value>> : std::true_type { + using return_type = + decltype(arg_mapper_impl().map(std::declval())); + }; + + template ::value)> + FMT_CONSTEXPR typename is_mappable::return_type map(const T& val) { + return arg_mapper_impl().map(val); + } + + template ::value)> + FMT_CONSTEXPR const T& map(const T& val) { + static_assert( + has_any_formatter::value, + "Cannot format argument. To enable the use of ostream operator<< " + "include fmt/ostream.h. Otherwise specialize the formatter struct " + "template and implement parse and format methods."); + return val; + } +}; + // A type constant after applying arg_mapper. template using mapped_type_constant =