NexusForce 1.0.0
A rigorously engineered full-stack C++ backend library.
载入中...
搜索中...
未找到
format.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_STRING_FORMAT_HPP__
2#define NEFORCE_CORE_STRING_FORMAT_HPP__
3
11
15NEFORCE_BEGIN_NAMESPACE__
16
22
34
50
58 char fill = ' ';
61 int width = 0;
62 int precision = -1;
63 bool uppercase = false;
64 bool alternate = false;
65 bool zero_pad = false;
66 bool show_sign = false;
67 bool space_sign = false;
68 const locale* loc = nullptr;
69};
70
72NEFORCE_BEGIN_INNER__
73
74NEFORCE_CONSTEXPR20 string uint_to_string_base(uint64_t value, const int base, const bool uppercase) {
75 if (value == 0) {
76 return "0";
77 }
78
79 string result;
80 result.reserve(20);
81
82 constexpr auto digits_lower = "0123456789abcdef";
83 constexpr auto digits_upper = "0123456789ABCDEF";
84 const auto* digits = uppercase ? digits_upper : digits_lower;
85
86 while (value > 0) {
87 const uint64_t remainder = value % base;
88 value /= base;
89 result.push_back(digits[remainder]);
90 }
91
92 result.reverse();
93 return result;
94}
95
96constexpr format_align to_number_alignment(const char c) {
97 switch (c) {
98 case '<':
99 return format_align::LEFT;
100 case '>':
101 return format_align::RIGHT;
102 case '^':
103 return format_align::CENTER;
104 case '=':
105 return format_align::NUMERIC;
106 default:
107 return format_align::DEFAULT;
108 }
109}
110
111constexpr format_type to_number_type(const char c) {
112 switch (c) {
113 case 'd':
114 return format_type::DECIMAL;
115 case 'b':
116 case 'B':
117 return format_type::BINARY;
118 case 'o':
119 return format_type::OCTAL;
120 case 'x':
121 case 'X':
122 return format_type::HEX;
123 case 'e':
124 case 'E':
125 return format_type::SCIENTIFIC;
126 case 'f':
127 case 'F':
128 return format_type::FIXED;
129 case 'g':
130 case 'G':
131 return format_type::GENERAL;
132 case 'c':
133 return format_type::CHAR;
134 default:
135 return format_type::DEFAULT;
136 }
137}
138
139constexpr format_options parse_number_format(const string_view& fmt_str) {
140 format_options options;
141 size_t pos = 0;
142
143 if (fmt_str.empty()) {
144 return options;
145 }
146
147 bool found_align = false;
148 if (pos + 1 < fmt_str.size()) {
149 const char first_char = fmt_str[pos];
150 const char second_char = fmt_str[pos + 1];
151
152 if (second_char == '<' || second_char == '>' || second_char == '^' || second_char == '=') {
153 if (first_char != '+' && first_char != '-' && first_char != ' ') {
154 options.fill = first_char;
155 options.align = to_number_alignment(second_char);
156 pos += 2;
157 found_align = true;
158 }
159 }
160 }
161
162 if (!found_align && pos < fmt_str.size()) {
163 const char c = fmt_str[pos];
164 if (c == '<' || c == '>' || c == '^' || c == '=') {
165 options.align = to_number_alignment(c);
166 ++pos;
167 }
168 }
169
170 if (pos < fmt_str.size()) {
171 const char c = fmt_str[pos];
172 if (c == '+') {
173 options.show_sign = true;
174 ++pos;
175 } else if (c == ' ') {
176 options.space_sign = true;
177 ++pos;
178 } else if (c == '-') {
179 ++pos;
180 if (pos < fmt_str.size()) {
181 const char next = fmt_str[pos];
182 if (next == '<' || next == '>' || next == '^' || next == '=') {
183 options.align = to_number_alignment(next);
184 ++pos;
185 }
186 }
187 }
188 }
189
190 if (pos < fmt_str.size() && fmt_str[pos] == '#') {
191 options.alternate = true;
192 ++pos;
193 }
194
195 if (pos < fmt_str.size() && fmt_str[pos] == '0' && options.fill == ' ' && options.align == format_align::DEFAULT) {
196 options.zero_pad = true;
197 options.fill = '0';
198 ++pos;
199 }
200
201 if (pos < fmt_str.size() && is_digit(fmt_str[pos])) {
202 int width = 0;
203 while (pos < fmt_str.size() && is_digit(fmt_str[pos])) {
204 width = width * 10 + (fmt_str[pos] - '0');
205 ++pos;
206 }
207 options.width = width;
208 }
209
210 if (pos < fmt_str.size() && fmt_str[pos] == '.') {
211 ++pos;
212 int precision = 0;
213 while (pos < fmt_str.size() && is_digit(fmt_str[pos])) {
214 precision = precision * 10 + (fmt_str[pos] - '0');
215 ++pos;
216 }
217 options.precision = precision;
218 }
219
220 if (pos < fmt_str.size()) {
221 const char c = fmt_str[pos];
222 options.type = to_number_type(c);
223 if (c == 'X' || c == 'E' || c == 'G' || c == 'B') {
224 options.uppercase = true;
225 }
226 ++pos;
227 }
228
229 return options;
230}
231
232
233NEFORCE_CONSTEXPR20 string apply_format_options(string raw, const format_options& options,
234 const bool is_numeric = false) {
235 char existing_sign = '\0';
236 if (!raw.empty() && (raw[0] == '-' || raw[0] == '+' || raw[0] == ' ')) {
237 char sign = raw[0];
238 raw = raw.tail(1);
239 existing_sign = sign;
240 }
241
242 string prefix;
243 if (options.alternate && is_numeric) {
244 switch (options.type) {
245 case format_type::HEX: {
246 prefix = options.uppercase ? "0X" : "0x";
247 break;
248 }
249 case format_type::BINARY: {
250 prefix = options.uppercase ? "0B" : "0b";
251 break;
252 }
253 case format_type::OCTAL: {
254 if (raw.empty() || raw[0] != '0') {
255 prefix = "0";
256 }
257 break;
258 }
259 default: {
260 break;
261 }
262 }
263 }
264
265 string sign_str;
266 if (existing_sign == '-') {
267 sign_str = "-";
268 } else if (options.show_sign) {
269 sign_str = "+";
270 } else if (options.space_sign) {
271 sign_str = " ";
272 }
273
274 const size_t content_len = sign_str.size() + prefix.size() + raw.size();
275 const size_t target_width = (options.width > 0) ? static_cast<size_t>(options.width) : 0;
276
277 const size_t pad_total = (content_len < target_width) ? target_width - content_len : 0;
278
279 format_align align = options.align;
280 if (align == format_align::DEFAULT) {
281 align = is_numeric ? format_align::RIGHT : format_align::LEFT;
282 }
283
284 if (options.zero_pad && is_numeric && align == format_align::RIGHT) {
285 align = format_align::NUMERIC;
286 }
287
288 if (align == format_align::NUMERIC && is_numeric) {
289 const char fill_char = options.fill;
290 string result;
291 result.reserve(target_width > 0 ? target_width : content_len);
292 result += sign_str;
293 result += prefix;
294 for (size_t i = 0; i < pad_total; ++i) {
295 result += fill_char;
296 }
297 result += raw;
298 return result;
299 }
300
301 const char fill_char = options.fill;
302 string left_pad;
303 string right_pad;
304
305 switch (align) {
306 case format_align::LEFT: {
307 right_pad = string(pad_total, fill_char);
308 break;
309 }
310 case format_align::CENTER: {
311 const size_t left_count = pad_total / 2;
312 const size_t right_count = pad_total - left_count;
313 left_pad = string(left_count, fill_char);
314 right_pad = string(right_count, fill_char);
315 break;
316 }
317 case format_align::RIGHT:
318 default: {
319 left_pad = string(pad_total, fill_char);
320 break;
321 }
322 }
323
324 string result;
325 result.reserve(target_width > 0 ? target_width : content_len);
326 result += left_pad;
327 result += sign_str;
328 result += prefix;
329 result += raw;
330 result += right_pad;
331 return result;
332}
333
334template <typename T, bool Signed>
335struct integer_formatter_impl {
336 NEFORCE_CONSTEXPR20 string operator()(const T value, const format_options& options) const {
337 using UT = conditional_t<Signed, make_unsigned_t<T>, T>;
338
339 const bool is_negative = Signed && (value < 0);
340 const UT abs_value = is_negative ? static_cast<UT>(0 - static_cast<UT>(value)) : static_cast<UT>(value);
341 const auto compatible = static_cast<uint64_t>(abs_value);
342
343 string raw;
344
345 switch (options.type) {
346 case format_type::BINARY: {
347 raw = inner::uint_to_string_base(compatible, 2, options.uppercase);
348 break;
349 }
350 case format_type::OCTAL: {
351 raw = inner::uint_to_string_base(compatible, 8, options.uppercase);
352 break;
353 }
354 case format_type::HEX: {
355 raw = inner::uint_to_string_base(compatible, 16, options.uppercase);
356 break;
357 }
358 case format_type::CHAR: {
359 return inner::apply_format_options(string(1, static_cast<char>(value)), options, false);
360 }
361 case format_type::DECIMAL:
362 case format_type::DEFAULT:
363 default: {
364 raw = inner::__int_to_string_dispatch(value);
365 return inner::apply_format_options(_NEFORCE move(raw), options, true);
366 }
367 }
368
369 if (is_negative) {
370 raw = "-" + raw;
371 }
372 return inner::apply_format_options(_NEFORCE move(raw), options, true);
373 }
374};
375
376NEFORCE_END_INNER__
378
387template <typename Number, typename Dummy = void>
389
394template <typename T>
402 NEFORCE_CONSTEXPR20 string operator()(const T& value, const format_options& options) const {
403 if (options.loc != nullptr && (options.type == format_type::DEFAULT || options.type == format_type::FIXED ||
404 options.type == format_type::GENERAL)) {
405 const int prec = (options.precision >= 0) ? options.precision : 2;
406 return options.loc->format_number(static_cast<double>(value), prec);
407 }
408 const int prec = (options.precision >= 0) ? options.precision : 6;
409 string raw;
410
411 switch (options.type) {
413 raw = _NEFORCE to_string_scientific(value, prec);
414 break;
415 }
416 case format_type::FIXED: {
417 raw = _NEFORCE to_string_fixed(value, prec);
418 break;
419 }
423 default: {
424 raw = _NEFORCE to_string_general(value, prec);
425 break;
426 }
427 }
428
429 if (options.uppercase) {
430 for (auto& c: raw) {
431 if (c == 'e') {
432 c = 'E';
433 break;
434 }
435 }
436 }
437
438 return inner::apply_format_options(_NEFORCE move(raw), options, true);
439 }
440};
441
446template <typename T>
454 NEFORCE_CONSTEXPR20 string operator()(const T value, const format_options& options) const {
455 if (options.loc != nullptr && options.type == format_type::DEFAULT) {
456 return options.loc->format_number(static_cast<int64_t>(value));
457 }
458 return inner::integer_formatter_impl<T, true>{}(value, options);
459 }
460};
461
466template <typename T>
474 NEFORCE_CONSTEXPR20 string operator()(const T value, const format_options& options) const {
475 if (options.loc != nullptr && options.type == format_type::DEFAULT) {
476 return options.loc->format_number(static_cast<int64_t>(value));
477 }
478 // NOLINTNEXTLINE(readability-implicit-bool-conversion)
479 return inner::integer_formatter_impl<T, false>{}(value, options);
480 }
481};
482
486template <>
487struct formatter<char> {
488 NEFORCE_CONSTEXPR20 string operator()(const char value, const format_options& options) const {
489 switch (options.type) {
492 case format_type::HEX:
494 return inner::integer_formatter_impl<int, true>{}(static_cast<int>(value), options);
495 }
496 default: {
497 break;
498 }
499 }
500 return inner::apply_format_options(string(1, value), options, false);
501 }
502};
503
504template <typename T>
506 NEFORCE_CONSTEXPR20 string operator()(const T value, const format_options& options) const {
507 return formatter<unpackage_t<T>>()(value.value(), options);
508 }
509};
510
514template <>
515struct formatter<bool> {
516 NEFORCE_CONSTEXPR20 string operator()(const bool value, const format_options& options) const {
517 switch (options.type) {
520 case format_type::HEX:
522 return inner::integer_formatter_impl<int, false>{}(static_cast<int>(value), options);
523 }
524 default: {
525 break;
526 }
527 }
528 return inner::apply_format_options(value ? "true" : "false", options, false);
529 }
530};
531
535template <>
537 NEFORCE_CONSTEXPR20 string operator()(const string& value, const format_options& options) const {
538 string raw = value;
539 if (options.precision >= 0 && raw.size() > static_cast<size_t>(options.precision)) {
540 raw = raw.head(static_cast<size_t>(options.precision));
541 }
542 return inner::apply_format_options(_NEFORCE move(raw), options, false);
543 }
544};
545
549template <>
551 NEFORCE_CONSTEXPR20 string operator()(const string_view value, const format_options& options) const {
552 return formatter<string>()(string(value), options);
553 }
554};
555
559template <>
560struct formatter<const char*> {
561 NEFORCE_CONSTEXPR20 string operator()(const char* value, const format_options& options) const {
562 if (value == nullptr) {
563 return inner::apply_format_options("nullptr", options, false);
564 }
565 return formatter<string>{}(string(value), options);
566 }
567};
568
572template <>
574 NEFORCE_CONSTEXPR20 string operator()(nullptr_t, const format_options& options) const {
575 return inner::apply_format_options("nullptr", options, false);
576 }
577};
578
582template <typename T>
584 NEFORCE_CONSTEXPR20 string operator()(const T* ptr, const format_options& options) const {
585 return inner::apply_format_options(_NEFORCE address_string(ptr), options, false);
586 }
587};
588
592template <>
593struct formatter<char*> {
594 NEFORCE_CONSTEXPR20 string operator()(char* value, const format_options& options) const {
595 return formatter<string>()(string(value), options);
596 }
597};
598
600NEFORCE_BEGIN_INNER__
601
602#ifdef NEFORCE_STANDARD_20
603
610template <size_t N>
611consteval bool validate_format_string(const char (&fmt)[N]) noexcept {
612 size_t brace_count = 0;
613 for (size_t i = 0; i < N - 1; ++i) {
614 if (fmt[i] == '{') {
615 if (i + 1 < N - 1 && fmt[i + 1] == '{') {
616 ++i;
617 continue;
618 }
619 ++brace_count;
620 } else if (fmt[i] == '}') {
621 if (i + 1 < N - 1 && fmt[i + 1] == '}') {
622 ++i;
623 continue;
624 }
625 if (brace_count == 0) {
626 return false;
627 }
628 --brace_count;
629 }
630 }
631 return brace_count == 0;
632}
633
634#endif
635
648template <size_t I, typename Tuple>
649NEFORCE_CONSTEXPR20 enable_if_t<I == tuple_size_v<Tuple>, string>
650format_get_and_apply(const size_t idx, const Tuple& args, const format_options& opts) {
651 NEFORCE_THROW_EXCEPTION(value_exception("Format argument index out of range"));
652}
653
654template <size_t I, typename Tuple>
655NEFORCE_CONSTEXPR20 enable_if_t<(I < tuple_size_v<Tuple>), string>
656format_get_and_apply(const size_t idx, const Tuple& args, const format_options& opts) {
657 if (idx == I) {
658 return formatter<decay_t<tuple_element_t<I, Tuple>>>()(_NEFORCE get<I>(args), opts);
659 }
660 return format_get_and_apply<I + 1, Tuple>(idx, args, opts);
661}
662
666NEFORCE_CONSTEXPR20 void format_impl(const string_view fmt, size_t& pos, string& out) {
667 while (pos < fmt.size()) {
668 if (fmt[pos] == '{') {
669 if (pos + 1 < fmt.size() && fmt[pos + 1] == '{') {
670 out += '{';
671 pos += 2;
672 } else {
673 NEFORCE_THROW_EXCEPTION(value_exception("Not enough arguments"));
674 }
675 } else if (fmt[pos] == '}') {
676 if (pos + 1 < fmt.size() && fmt[pos + 1] == '}') {
677 out += '}';
678 pos += 2;
679 } else {
680 NEFORCE_THROW_EXCEPTION(value_exception("Unmatched '}'"));
681 }
682 } else {
683 out += fmt[pos++];
684 }
685 }
686}
687
697template <typename Tuple>
698NEFORCE_CONSTEXPR20 void format_impl(const string_view fmt, size_t& pos, string& out, const Tuple& args,
699 size_t& next_seq) {
700 while (pos < fmt.size()) {
701 if (fmt[pos] == '{') {
702 if (pos + 1 < fmt.size() && fmt[pos + 1] == '{') {
703 out += '{';
704 pos += 2;
705 continue;
706 }
707 ++pos;
708 size_t end_pos = pos;
709 int depth = 1;
710 while (end_pos < fmt.size() && depth > 0) {
711 if (fmt[end_pos] == '{') {
712 ++depth;
713 } else if (fmt[end_pos] == '}') {
714 --depth;
715 }
716 if (depth > 0) {
717 ++end_pos;
718 }
719 }
720 if (depth != 0) {
721 NEFORCE_THROW_EXCEPTION(value_exception("Unmatched '{' in format string"));
722 }
723
724 const string_view spec_str = fmt.substr(pos, end_pos - pos);
725 pos = end_pos + 1;
726
727 format_options opts;
728 size_t arg_idx = next_seq;
729
730 if (spec_str.empty()) {
731 // {} — sequential consumption
732 opts = inner::parse_number_format("");
733 ++next_seq;
734 } else if (is_digit(spec_str[0])) {
735 // {N} or {N:options} — positional
736 size_t num_end = 0;
737 arg_idx = 0;
738 while (num_end < spec_str.size() && is_digit(spec_str[num_end])) {
739 arg_idx = arg_idx * 10 + static_cast<size_t>(spec_str[num_end] - '0');
740 ++num_end;
741 }
742 const string_view rest = spec_str.tail(num_end);
743 if (rest.empty()) {
744 opts = inner::parse_number_format("");
745 } else if (rest[0] == ':') {
746 opts = inner::parse_number_format(rest.tail(1));
747 } else {
748 NEFORCE_THROW_EXCEPTION(value_exception("Invalid format specifier"));
749 }
750 } else if (spec_str[0] == ':') {
751 // {:options} — sequential consumption with format options
752 opts = inner::parse_number_format(spec_str.tail(1));
753 ++next_seq;
754 } else {
755 NEFORCE_THROW_EXCEPTION(value_exception("Invalid format specifier"));
756 }
757
758 if (arg_idx >= tuple_size_v<Tuple>) {
759 NEFORCE_THROW_EXCEPTION(value_exception("Format argument index out of range"));
760 }
761
762 out += inner::format_get_and_apply<0, Tuple>(arg_idx, args, opts);
763 } else if (fmt[pos] == '}') {
764 if (pos + 1 < fmt.size() && fmt[pos + 1] == '}') {
765 out += '}';
766 pos += 2;
767 } else {
768 NEFORCE_THROW_EXCEPTION(value_exception("Unmatched '}' in format string"));
769 }
770 } else {
771 out += fmt[pos++];
772 }
773 }
774}
775
779template <typename First, typename... Rest>
780NEFORCE_CONSTEXPR20 void format_impl(const string_view fmt, size_t& pos, string& out, First&& first, Rest&&... rest) {
781 const auto args = _NEFORCE forward_as_tuple(_NEFORCE forward<First>(first), _NEFORCE forward<Rest>(rest)...);
782 size_t next_seq = 0;
783 inner::format_impl(fmt, pos, out, args, next_seq);
784}
785
786NEFORCE_END_INNER__
788
804template <typename... Args, enable_if_t<(sizeof...(Args) > 0), int> = 0>
805NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string format(const string_view fmt, Args&&... args) {
806 string result;
807 result.reserve(fmt.size() + sizeof...(Args) * 8);
808 const auto args_tuple = _NEFORCE forward_as_tuple(_NEFORCE forward<Args>(args)...);
809 size_t next_seq = 0;
810 size_t pos = 0;
811 inner::format_impl(fmt, pos, result, args_tuple, next_seq);
812 return result;
813}
814
827template <size_t N, typename... Args, enable_if_t<(sizeof...(Args) > 0), int> = 0>
828NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string format(const char (&fmt)[N], Args&&... args) {
829 return _NEFORCE format(string_view(fmt, N - 1), _NEFORCE forward<Args>(args)...);
830}
831
842NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string
843format_named(const string_view fmt, const std::initializer_list<pair<const char*, string_view>> params) {
844 string result;
845 result.reserve(fmt.size());
846 size_t i = 0;
847
848 while (i < fmt.size()) {
849 if (fmt[i] == '{' && i + 1 < fmt.size()) {
850 if (fmt[i + 1] == '{') {
851 result += '{';
852 i += 2;
853 continue;
854 }
855
856 size_t j = i + 1;
857 while (j < fmt.size() && fmt[j] != '}') {
858 ++j;
859 }
860 if (j >= fmt.size()) {
861 result += fmt[i++];
862 continue;
863 }
864
865 const string_view name = fmt.view(i + 1, j - (i + 1));
866 bool found = false;
867 for (const auto& param: params) {
868 const string_view key(param.first);
869 if (key == name) {
870 result += param.second;
871 found = true;
872 break;
873 }
874 }
875 if (!found) {
876 result += fmt.view(i, j - i + 1);
877 }
878 i = j + 1;
879 } else if (fmt[i] == '}' && i + 1 < fmt.size() && fmt[i + 1] == '}') {
880 result += '}';
881 i += 2;
882 } else {
883 result += fmt[i++];
884 }
885 }
886 return result;
887}
888
900template <typename... Args, enable_if_t<(sizeof...(Args) > 0), int> = 0>
901NEFORCE_NODISCARD string format(const locale& loc, const string_view fmt, Args&&... args) {
902 string result;
903 result.reserve(fmt.size() * 2);
904 format_options opts;
905 opts.loc = &loc;
906 format_impl(result, fmt, opts, _NEFORCE forward<Args>(args)...);
907 return result;
908}
909 // Format
911
912NEFORCE_END_NAMESPACE__
913#endif // NEFORCE_CORE_STRING_FORMAT_HPP__
constexpr basic_string_view tail(const size_type off=0) const
获取尾部子串
constexpr size_type size() const noexcept
获取字符串长度
constexpr basic_string_view substr(const size_type off=0, const size_type count=npos) const
获取子视图
constexpr basic_string_view view(const size_type off, const size_type count=npos) const
获取子视图
constexpr size_type size() const noexcept
获取字符数
constexpr basic_string head(const size_type count=npos) const
获取头部子串
constexpr void reserve(const size_type n)
预留容量
区域设置管理类
string format_number(int64_t value) const
格式化整数
constexpr T && forward(remove_reference_t< T > &x) noexcept
完美转发左值
constexpr bool is_unpackaged_v
is_unpackaged的便捷变量模板
constexpr bool is_signed_v
is_signed的便捷变量模板
constexpr bool is_floating_point_v
is_floating_point的便捷变量模板
constexpr bool is_unsigned_v
is_unsigned的便捷变量模板
constexpr bool is_standard_integral_v
is_standard_integral的便捷变量模板
constexpr bool is_base_of_v
is_base_of的便捷变量模板
constexpr bool is_digit(const CharT c) noexcept
检查字符是否为数字
long int64_t
64位有符号整数类型
unsigned long uint64_t
64位无符号整数类型
unsigned char uint8_t
8位无符号整数类型
decltype(nullptr) nullptr_t
空指针类型
constexpr string format(const string_view fmt, Args &&... args)
格式化字符串
format_type
数值类型格式枚举
constexpr string format_named(const string_view fmt, const std::initializer_list< pair< const char *, string_view > > params)
命名参数格式化
format_align
对齐方式枚举
@ DECIMAL
十进制 'd' / 'f' / 'g'
@ HEX
十六进制 'x' / 'X'
@ DEFAULT
默认(由类型决定)
@ OCTAL
八进制 'o'
@ BINARY
二进制 'b'
@ GENERAL
通用浮点 'g' / 'G'
@ SCIENTIFIC
科学计数法 'e' / 'E'
@ FIXED
固定小数 'f'
@ DEFAULT
默认(数字右对齐,其他左对齐)
@ NUMERIC
符号感知填充 '='
constexpr Iterator next(Iterator iter, iter_difference_t< Iterator > n=1)
获取迭代器的后一个位置
constexpr int sign(const T &value) noexcept
获取数值的符号
constexpr bool is_negative(const T x) noexcept
检查浮点数是否为负数
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
constexpr string to_string_general(T x, int precision=6)
将浮点数转换为字符串(通用格式)
constexpr string to_string_fixed(T x, int precision=6)
将浮点数转换为字符串(固定小数格式)
constexpr string to_string_scientific(T x, int precision=6)
将浮点数转换为字符串(科学计数法格式)
basic_string< char > string
字符字符串
constexpr string address_string(const void *p)
将指针转换为十六进制地址字符串
basic_string_view< char > string_view
字符字符串视图
constexpr tuple< Types &&... > forward_as_tuple(Types &&... args) noexcept
创建转发引用元组
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名
区域设置
char fill
填充字符
bool uppercase
是否大写
bool zero_pad
是否零填充
bool space_sign
是否空格占位符号 ' '
format_align align
对齐方式
int width
最小宽度(0表示不限制)
bool alternate
是否备用格式(# 前缀)
const locale * loc
locale 指针,非空时进行 locale 感知格式化
format_type type
类型
int precision
精度(-1表示默认)
bool show_sign
是否强制显示符号 '+'
constexpr string operator()(const T &value, const format_options &options) const
格式化浮点数
constexpr string operator()(const T value, const format_options &options) const
格式化有符号整数
constexpr string operator()(const T value, const format_options &options) const
格式化无符号整数
格式化器主模板
存储两个值的元组对
类型到字符串的转换函数
元组实现