@@ -654,6 +654,14 @@ concept _Formattable_with = semiregular<_Formatter>
654
654
{ __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
655
655
};
656
656
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
+
657
665
template <class _Ty, class _CharT>
658
666
inline constexpr bool _Is_basic_string_like_for = false;
659
667
@@ -707,15 +715,23 @@ public:
707
715
using _Td = remove_const_t<_Ty>;
708
716
// doesn't drop const-qualifier per an unnumbered LWG issue
709
717
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
+
710
730
typename _Context::template formatter_type<_Td> _Formatter;
711
731
_Parse_ctx.advance_to(_Formatter.parse(_Parse_ctx));
712
732
_Format_ctx.advance_to(
713
733
_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
+ }) {}
719
735
720
736
void format(basic_format_parse_context<_CharType>& _Parse_ctx, _Context& _Format_ctx) const {
721
737
_Format(_Parse_ctx, _Format_ctx, _Ptr);
@@ -3711,19 +3727,31 @@ _EXPORT_STD using wformat_args = basic_format_args<wformat_context>;
3711
3727
3712
3728
_EXPORT_STD template <class _Context = format_context, class... _Args>
3713
3729
_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
+ }
3718
3740
return _Format_arg_store<_Context, _Args...>{_Vals...};
3719
3741
}
3720
3742
3721
3743
_EXPORT_STD template <class... _Args>
3722
3744
_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
+ }
3727
3755
return _Format_arg_store<wformat_context, _Args...>{_Vals...};
3728
3756
}
3729
3757
0 commit comments