Skip to content

Commit ae8a5c5

Browse files
Conditionally emit special diagnostic message for lack of const
Also emit `static_assert` error messages for `basic_format_arg::handle`.
1 parent d6efe94 commit ae8a5c5

File tree

1 file changed

+41
-13
lines changed

1 file changed

+41
-13
lines changed

stl/inc/format

+41-13
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,14 @@ concept _Formattable_with = semiregular<_Formatter>
654654
{ __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
655655
};
656656

657+
template <class _Ty, class _Context, class _Formatter = _Context::template formatter_type<remove_const_t<_Ty>>>
658+
concept _Formattable_with_non_const = semiregular<_Formatter>
659+
&& requires(_Formatter& __f, _Ty&& __t, _Context __fc,
660+
basic_format_parse_context<typename _Context::char_type> __pc) {
661+
{ __f.parse(__pc) } -> same_as<typename decltype(__pc)::iterator>;
662+
{ __f.format(__t, __fc) } -> same_as<typename _Context::iterator>;
663+
};
664+
657665
template <class _Ty, class _CharT>
658666
inline constexpr bool _Is_basic_string_like_for = false;
659667

@@ -707,15 +715,23 @@ public:
707715
using _Td = remove_const_t<_Ty>;
708716
// doesn't drop const-qualifier per an unnumbered LWG issue
709717
using _Tq = conditional_t<_Formattable_with<const _Ty, _Context>, const _Ty, _Ty>;
718+
if constexpr (_Formattable_with_non_const<_Tq, _Context>) {
719+
static_assert(_Formattable_with<_Tq, _Context>,
720+
"The format() member function can't be called on const formatter<T>. "
721+
"To make the formatter usable, add const to format(). "
722+
"See N4971 [format.arg]/12, [format.formattable], and [formatter.requirements].");
723+
} else {
724+
static_assert(_Formattable_with<_Tq, _Context>,
725+
"Cannot format an argument. "
726+
"To make this type formattable, provide a formatter<T> specialization. "
727+
"See N4971 [format.arg]/12, [format.formattable], and [formatter.requirements].");
728+
}
729+
710730
typename _Context::template formatter_type<_Td> _Formatter;
711731
_Parse_ctx.advance_to(_Formatter.parse(_Parse_ctx));
712732
_Format_ctx.advance_to(
713733
_Formatter.format(*const_cast<_Tq*>(static_cast<const _Td*>(_Ptr)), _Format_ctx));
714-
}) {
715-
// ditto doesn't drop const-qualifier
716-
using _Tq = conditional_t<_Formattable_with<const _Ty, _Context>, const _Ty, _Ty>;
717-
static_assert(_Formattable_with<_Tq, _Context>);
718-
}
734+
}) {}
719735

720736
void format(basic_format_parse_context<_CharType>& _Parse_ctx, _Context& _Format_ctx) const {
721737
_Format(_Parse_ctx, _Format_ctx, _Ptr);
@@ -3711,19 +3727,31 @@ _EXPORT_STD using wformat_args = basic_format_args<wformat_context>;
37113727

37123728
_EXPORT_STD template <class _Context = format_context, class... _Args>
37133729
_NODISCARD auto make_format_args(_Args&... _Vals) {
3714-
// TRANSITION, should cite the new working draft
3715-
static_assert((_Formattable_with<remove_const_t<_Args>, _Context> && ...),
3716-
"Cannot format an argument. To make type T formattable, provide a formatter<T> specialization. "
3717-
"See N4964 [format.arg.store]/2 (along with modification in P2905R2) and [formatter.requirements].");
3730+
if constexpr ((_Formattable_with_non_const<remove_const_t<_Args>, _Context> && ...)) {
3731+
static_assert((_Formattable_with<remove_const_t<_Args>, _Context> && ...),
3732+
"The format() member function can't be called on const formatter<T>. "
3733+
"To make the formatter usable, add const to format(). "
3734+
"See N4971 [format.arg.store]/2 and [formatter.requirements].");
3735+
} else {
3736+
static_assert((_Formattable_with<remove_const_t<_Args>, _Context> && ...),
3737+
"Cannot format an argument. To make T formattable, provide a formatter<T> specialization. "
3738+
"See N4971 [format.arg.store]/2 and [formatter.requirements].");
3739+
}
37183740
return _Format_arg_store<_Context, _Args...>{_Vals...};
37193741
}
37203742

37213743
_EXPORT_STD template <class... _Args>
37223744
_NODISCARD auto make_wformat_args(_Args&... _Vals) {
3723-
// TRANSITION, should cite the new working draft
3724-
static_assert((_Formattable_with<remove_const_t<_Args>, wformat_context> && ...),
3725-
"Cannot format an argument. To make type T formattable, provide a formatter<T> specialization. "
3726-
"See N4964 [format.arg.store]/2 (along with modification in P2905R2) and [formatter.requirements].");
3745+
if constexpr ((_Formattable_with_non_const<remove_const_t<_Args>, wformat_context> && ...)) {
3746+
static_assert((_Formattable_with<remove_const_t<_Args>, wformat_context> && ...),
3747+
"The format() member function can't be called on const formatter<T>. "
3748+
"To make the formatter usable, add const to format(). "
3749+
"See N4971 [format.arg.store]/2 and [formatter.requirements].");
3750+
} else {
3751+
static_assert((_Formattable_with<remove_const_t<_Args>, wformat_context> && ...),
3752+
"Cannot format an argument. To make this type formattable, provide a formatter<T> specialization. "
3753+
"See N4971 [format.arg.store]/2 and [formatter.requirements].");
3754+
}
37273755
return _Format_arg_store<wformat_context, _Args...>{_Vals...};
37283756
}
37293757

0 commit comments

Comments
 (0)