@@ -42,6 +42,8 @@ enum class format_sign_option
4242template <typename ParseContext>
4343constexpr auto parse_impl (ParseContext &ctx)
4444{
45+ using CharType = typename ParseContext::char_type;
46+
4547 auto sign_character = format_sign_option::minus;
4648 auto it {ctx.begin ()};
4749 int ctx_precision = -1 ;
@@ -51,7 +53,7 @@ constexpr auto parse_impl(ParseContext &ctx)
5153 bool use_locale = false ;
5254
5355 // Check for the locale character
54- if (*it == ' L' )
56+ if (*it == static_cast <CharType>( ' L' ) )
5557 {
5658 use_locale = true ;
5759 ++it;
@@ -62,15 +64,15 @@ constexpr auto parse_impl(ParseContext &ctx)
6264 {
6365 switch (*it)
6466 {
65- case ' -' :
67+ case static_cast <CharType>( ' -' ) :
6668 sign_character = format_sign_option::minus;
6769 ++it;
6870 break ;
69- case ' +' :
71+ case static_cast <CharType>( ' +' ) :
7072 sign_character = format_sign_option::plus;
7173 ++it;
7274 break ;
73- case ' ' :
75+ case static_cast <CharType>( ' ' ) :
7476 sign_character = format_sign_option::space;
7577 ++it;
7678 break ;
@@ -80,26 +82,26 @@ constexpr auto parse_impl(ParseContext &ctx)
8082 }
8183
8284 // Check for a padding character
83- while (it != ctx.end () && *it >= ' 0' && *it <= ' 9' )
85+ while (it != ctx.end () && *it >= static_cast <CharType>( ' 0' ) && *it <= static_cast <CharType>( ' 9' ) )
8486 {
85- padding_digits = padding_digits * 10 + (*it - ' 0' );
87+ padding_digits = padding_digits * 10 + (*it - static_cast <CharType>( ' 0' ) );
8688 ++it;
8789 }
8890
8991 // If there is a . then we need to capture the precision argument
90- if (it != ctx.end () && *it == ' .' )
92+ if (it != ctx.end () && *it == static_cast <CharType>( ' .' ) )
9193 {
9294 ++it;
9395 ctx_precision = 0 ;
94- while (it != ctx.end () && *it >= ' 0' && *it <= ' 9' )
96+ while (it != ctx.end () && *it >= static_cast <CharType>( ' 0' ) && *it <= static_cast <CharType>( ' 9' ) )
9597 {
96- ctx_precision = ctx_precision * 10 + (*it - ' 0' );
98+ ctx_precision = ctx_precision * 10 + (*it - static_cast <CharType>( ' 0' ) );
9799 ++it;
98100 }
99101 }
100102
101103 // Lastly we capture the format to include if it's upper case
102- if (it != ctx.end () && *it != ' }' )
104+ if (it != ctx.end () && *it != static_cast <CharType>( ' }' ) )
103105 {
104106 switch (*it)
105107 {
@@ -152,20 +154,33 @@ constexpr auto parse_impl(ParseContext &ctx)
152154 }
153155
154156 // Verify we're at the closing brace
155- if (it != ctx.end () && *it != ' }' )
157+ if (it != ctx.end () && *it != static_cast <CharType>( ' }' ) )
156158 {
157159 BOOST_DECIMAL_THROW_EXCEPTION (std::format_error (" Expected '}' in format string" )); // LCOV_EXCL_LINE
158160 }
159161
160162 return std::make_tuple (ctx_precision, fmt, is_upper, padding_digits, sign_character, use_locale, it);
161163}
162164
165+ template <typename >
166+ struct formattable_character_type : std::false_type {};
167+
168+ template <>
169+ struct formattable_character_type <char > : std::true_type {};
170+
171+ template <>
172+ struct formattable_character_type <wchar_t > : std::true_type {};
173+
174+ template <typename CharT>
175+ inline constexpr bool is_formattable_character_type_v = formattable_character_type<CharT>::value;
176+
163177} // Namespace boost::decimal::detail
164178
165179namespace std {
166180
167- template <boost::decimal::detail::concepts::decimal_floating_point_type T>
168- struct formatter <T>
181+ template <boost::decimal::detail::concepts::decimal_floating_point_type T, typename CharT>
182+ requires boost::decimal::detail::is_formattable_character_type_v<CharT>
183+ struct formatter <T, CharT>
169184{
170185 boost::decimal::chars_format fmt;
171186 boost::decimal::detail::format_sign_option sign;
@@ -182,7 +197,7 @@ struct formatter<T>
182197 use_locale(false )
183198 {}
184199
185- constexpr auto parse (format_parse_context & ctx)
200+ constexpr auto parse (basic_format_parse_context<CharT>& ctx)
186201 {
187202 const auto res {boost::decimal::detail::parse_impl (ctx)};
188203
@@ -202,6 +217,9 @@ struct formatter<T>
202217 using namespace boost ::decimal;
203218 using namespace boost ::decimal::detail;
204219
220+ using CharType = FormatContext::char_type;
221+ static_assert (is_formattable_character_type_v<CharType>, " This is an unsupported character type. Only char and wchar_t can be used with std::format" );
222+
205223 std::array<char , 128 > buffer {};
206224 auto buffer_front = buffer.data ();
207225 bool has_sign {false };
@@ -276,7 +294,22 @@ struct formatter<T>
276294 s.resize (initial_length + offset);
277295 }
278296
279- return std::format_to (ctx.out (), " {}" , s);
297+ // std <format> only supports char and wchar_t
298+ if constexpr (std::is_same_v<CharType, char >)
299+ {
300+ return std::format_to (ctx.out (), " {}" , s);
301+ }
302+ else
303+ {
304+ std::wstring result;
305+ result.reserve (s.size ());
306+ for (const char c : s)
307+ {
308+ result.push_back (static_cast <CharType>(static_cast <unsigned char >(c)));
309+ }
310+
311+ return std::format_to (ctx.out (), L" {}" , result);
312+ }
280313 }
281314};
282315
0 commit comments