Remove static_assert from arg_mapper

This commit is contained in:
Victor Zverovich 2021-08-26 18:47:59 -07:00
parent 8b0cb944da
commit 043e3b3429
2 changed files with 76 additions and 41 deletions

View File

@ -1127,8 +1127,9 @@ constexpr bool is_arithmetic_type(type t) {
}
struct unformattable {};
struct unformattable_pointer : unformattable {};
struct unformattable_char : unformattable {};
struct unformattable_const : unformattable {};
struct unformattable_pointer : unformattable {};
template <typename Char> struct string_value {
const Char* data;
@ -1207,8 +1208,9 @@ template <typename Context> class value {
fallback_formatter<value_type, char_type>>>;
}
value(unformattable);
value(unformattable_pointer);
value(unformattable_char);
value(unformattable_const) {}
value(unformattable_pointer);
private:
// Formats an argument of a custom type, such as a user-defined class.
@ -1365,17 +1367,37 @@ template <typename Context> struct arg_mapper {
static_cast<typename std::underlying_type<T>::type>(val))) {
return map(static_cast<typename std::underlying_type<T>::type>(val));
}
template <typename T, typename U = remove_cvref_t<T>>
using formattable =
bool_constant<is_const_formattable<U, Context>() ||
!std::is_const<remove_reference_t<T>>::value ||
has_fallback_formatter<U, char_type>::value>;
#if FMT_MSC_VER != 0 && FMT_MSC_VER < 1910
// Workaround a bug in MSVC.
template <typename T> FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& {
return val;
}
#else
template <typename T, FMT_ENABLE_IF(formattable<T>::value)>
FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& {
return val;
}
template <typename T, FMT_ENABLE_IF(!formattable<T>::value)>
FMT_CONSTEXPR FMT_INLINE auto do_map(T&&) -> unformattable_const {
return {};
}
#endif
template <typename T, typename U = remove_cvref_t<T>,
FMT_ENABLE_IF(!is_string<U>::value && !is_char<U>::value &&
!std::is_array<U>::value &&
(has_formatter<U, Context>::value ||
has_fallback_formatter<U, char_type>::value))>
FMT_CONSTEXPR FMT_INLINE auto map(T&& val) -> T& {
static_assert(is_const_formattable<U, Context>() ||
!std::is_const<remove_reference_t<T>>() ||
has_fallback_formatter<U, char_type>(),
"cannot format a const argument");
return val;
FMT_CONSTEXPR FMT_INLINE auto map(T&& val)
-> decltype(this->do_map(std::forward<T>(val))) {
return do_map(std::forward<T>(val));
}
template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
@ -1616,13 +1638,18 @@ FMT_CONSTEXPR FMT_INLINE auto make_arg(T&& val) -> value<Context> {
// a pointer cast it to "void *" or "const void *". In particular, this
// forbids formatting of "[const] volatile char *" which is printed as bool
// by iostreams.
constexpr bool void_ptr =
constexpr bool formattable_pointer =
!std::is_same<decltype(arg), const unformattable_pointer&>::value;
static_assert(void_ptr, "Formatting of non-void pointers is disallowed.");
static_assert(formattable_pointer,
"Formatting of non-void pointers is disallowed.");
constexpr bool same_char =
constexpr bool formattable_char =
!std::is_same<decltype(arg), const unformattable_char&>::value;
static_assert(same_char, "Mixing character types is disallowed.");
static_assert(formattable_char, "Mixing character types is disallowed.");
constexpr bool formattable_const =
!std::is_same<decltype(arg), const unformattable_const&>::value;
static_assert(formattable_const, "Cannot format a const argument.");
constexpr bool formattable =
!std::is_same<decltype(arg), const unformattable&>::value;

View File

@ -703,6 +703,35 @@ TEST(core_test, has_formatter) {
"");
}
struct const_formattable {};
struct nonconst_formattable {};
FMT_BEGIN_NAMESPACE
template <> struct formatter<const_formattable> {
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(const const_formattable&, format_context& ctx)
-> decltype(ctx.out()) {
auto test = string_view("test");
return std::copy_n(test.data(), test.size(), ctx.out());
}
};
template <> struct formatter<nonconst_formattable> {
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(nonconst_formattable&, format_context& ctx)
-> decltype(ctx.out()) {
auto test = string_view("test");
return std::copy_n(test.data(), test.size(), ctx.out());
}
};
FMT_END_NAMESPACE
TEST(core_test, is_formattable) {
static_assert(fmt::is_formattable<signed char*>::value, "");
static_assert(fmt::is_formattable<unsigned char*>::value, "");
@ -717,6 +746,14 @@ TEST(core_test, is_formattable) {
static_assert(!fmt::is_formattable<disabled_formatter>::value, "");
static_assert(fmt::is_formattable<disabled_formatter_convertible>::value, "");
static_assert(fmt::is_formattable<const_formattable&>::value, "");
static_assert(fmt::is_formattable<const const_formattable&>::value, "");
static_assert(fmt::is_formattable<nonconst_formattable&>::value, "");
#if !FMT_MSC_VER || FMT_MSC_VER >= 1910
static_assert(!fmt::is_formattable<const nonconst_formattable&>::value, "");
#endif
static_assert(!fmt::is_formattable<signed char*, wchar_t>::value, "");
static_assert(!fmt::is_formattable<unsigned char*, wchar_t>::value, "");
static_assert(!fmt::is_formattable<const signed char*, wchar_t>::value, "");
@ -854,35 +891,6 @@ TEST(core_test, adl) {
fmt::print(stdout, "{}", s);
}
struct const_formattable {};
struct nonconst_formattable {};
FMT_BEGIN_NAMESPACE
template <> struct formatter<const_formattable> {
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(const const_formattable&, format_context& ctx)
-> decltype(ctx.out()) {
auto test = string_view("test");
return std::copy_n(test.data(), test.size(), ctx.out());
}
};
template <> struct formatter<nonconst_formattable> {
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(nonconst_formattable&, format_context& ctx)
-> decltype(ctx.out()) {
auto test = string_view("test");
return std::copy_n(test.data(), test.size(), ctx.out());
}
};
FMT_END_NAMESPACE
TEST(core_test, is_const_formattable) {
EXPECT_TRUE((fmt::detail::is_const_formattable<const_formattable,
fmt::format_context>()));