Skip to content

Commit 33854e5

Browse files
<format>: Conditionally emit special diagnostic message for lack of const (#4461)
Co-authored-by: Stephan T. Lavavej <[email protected]>
1 parent 3ec144e commit 33854e5

File tree

1 file changed

+32
-14
lines changed

1 file changed

+32
-14
lines changed

stl/inc/format

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,14 @@ concept _Formattable_with = semiregular<_Formatter>
658658
{ __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
659659
};
660660

661+
template <class _Ty, class _Context, class _Formatter = _Context::template formatter_type<remove_const_t<_Ty>>>
662+
concept _Formattable_with_non_const = semiregular<_Formatter>
663+
&& requires(_Formatter& __f, _Ty&& __t, _Context __fc,
664+
basic_format_parse_context<typename _Context::char_type> __pc) {
665+
{ __f.parse(__pc) } -> same_as<typename decltype(__pc)::iterator>;
666+
{ __f.format(__t, __fc) } -> same_as<typename _Context::iterator>;
667+
};
668+
661669
template <class _Ty, class _CharT>
662670
inline constexpr bool _Is_basic_string_like_for = false;
663671

@@ -711,15 +719,23 @@ public:
711719
using _Td = remove_const_t<_Ty>;
712720
// doesn't drop const-qualifier per an unnumbered LWG issue
713721
using _Tq = conditional_t<_Formattable_with<const _Ty, _Context>, const _Ty, _Ty>;
722+
if constexpr (_Formattable_with_non_const<_Tq, _Context>) {
723+
static_assert(_Formattable_with<_Tq, _Context>,
724+
"The format() member function can't be called on const formatter<T>. "
725+
"To make the formatter usable, add const to format(). "
726+
"See N4971 [format.arg]/12, [format.formattable], and [formatter.requirements].");
727+
} else {
728+
static_assert(_Formattable_with<_Tq, _Context>,
729+
"Cannot format an argument. "
730+
"To make this type formattable, provide a formatter<T> specialization. "
731+
"See N4971 [format.arg]/12, [format.formattable], and [formatter.requirements].");
732+
}
733+
714734
typename _Context::template formatter_type<_Td> _Formatter;
715735
_Parse_ctx.advance_to(_Formatter.parse(_Parse_ctx));
716736
_Format_ctx.advance_to(
717737
_Formatter.format(*const_cast<_Tq*>(static_cast<const _Td*>(_Ptr)), _Format_ctx));
718-
}) {
719-
// ditto doesn't drop const-qualifier
720-
using _Tq = conditional_t<_Formattable_with<const _Ty, _Context>, const _Ty, _Ty>;
721-
static_assert(_Formattable_with<_Tq, _Context>);
722-
}
738+
}) {}
723739

724740
void format(basic_format_parse_context<_CharType>& _Parse_ctx, _Context& _Format_ctx) const {
725741
_Format(_Parse_ctx, _Format_ctx, _Ptr);
@@ -3715,20 +3731,22 @@ _EXPORT_STD using wformat_args = basic_format_args<wformat_context>;
37153731

37163732
_EXPORT_STD template <class _Context = format_context, class... _Args>
37173733
_NODISCARD auto make_format_args(_Args&... _Vals) {
3718-
// TRANSITION, should cite the new working draft
3719-
static_assert((_Formattable_with<remove_const_t<_Args>, _Context> && ...),
3720-
"Cannot format an argument. To make type T formattable, provide a formatter<T> specialization. "
3721-
"See N4964 [format.arg.store]/2 (along with modification in P2905R2) and [formatter.requirements].");
3734+
if constexpr ((_Formattable_with_non_const<remove_const_t<_Args>, _Context> && ...)) {
3735+
static_assert((_Formattable_with<remove_const_t<_Args>, _Context> && ...),
3736+
"The format() member function can't be called on const formatter<T>. "
3737+
"To make the formatter usable, add const to format(). "
3738+
"See N4971 [format.arg.store]/2 and [formatter.requirements].");
3739+
} else {
3740+
static_assert((_Formattable_with<remove_const_t<_Args>, _Context> && ...),
3741+
"Cannot format an argument. To make T formattable, provide a formatter<T> specialization. "
3742+
"See N4971 [format.arg.store]/2 and [formatter.requirements].");
3743+
}
37223744
return _Format_arg_store<_Context, _Args...>{_Vals...};
37233745
}
37243746

37253747
_EXPORT_STD template <class... _Args>
37263748
_NODISCARD auto make_wformat_args(_Args&... _Vals) {
3727-
// TRANSITION, should cite the new working draft
3728-
static_assert((_Formattable_with<remove_const_t<_Args>, wformat_context> && ...),
3729-
"Cannot format an argument. To make type T formattable, provide a formatter<T> specialization. "
3730-
"See N4964 [format.arg.store]/2 (along with modification in P2905R2) and [formatter.requirements].");
3731-
return _Format_arg_store<wformat_context, _Args...>{_Vals...};
3749+
return _STD make_format_args<wformat_context>(_Vals...);
37323750
}
37333751

37343752
_FMT_P2286_BEGIN

0 commit comments

Comments
 (0)