Skip to content

Commit

Permalink
実装例を追加
Browse files Browse the repository at this point in the history
  • Loading branch information
tetsurom committed Apr 1, 2024
1 parent d548d89 commit 5398590
Showing 1 changed file with 92 additions and 0 deletions.
92 changes: 92 additions & 0 deletions reference/format/vformat_to.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,98 @@ namespace std {
書式文字列が正しくなかったり、フォーマット実行時に失敗したりした場合、[`format_error`](format_error.md)を投げる。
## 実装例
```cpp
template<class ParseContext, class FormatContext>
struct ArgVisitor {
ParseContext& pctx;
FormatContext& fctx;
void operator()(std::monostate) {
}
using handle = std::basic_format_arg<FormatContext>::handle;
void operator()(const handle& handle) {
handle.format(pctx, fctx);
}
template<class T>
void operator()(const T& arg) {
using Formatter = FormatContext::template formatter_type<T>;
Formatter formatter;
pctx.advance_to(formatter.parse(pctx));
fctx.advance_to(formatter.format(arg, fctx));
}
};
template<std::output_iterator<char> Out, class Context = basic_format_context<Out, char>>
Out vformat_to(Out out, std::string_view fmt, std::basic_format_args<Context> args) {
using ParseContext = std::basic_format_parse_context<decltype(fmt)::value_type>;
ParseContext pctx{fmt};
Context fctx{out, args}; // このコンストラクタの存在は未規定
ArgVisitor<ParseContext, Context> visitor{pctx, fctx};
size_t next_arg_index = 0;
while (!std::ranges::empty(pctx)) {
auto it = pctx.begin();
if (*it == '{') {
++it;
if (it == pctx.end()) {
throw std::format_error("invalid format");
} else if (*it != '{') {
// インデックスを解析する
size_t index;
if (auto [ptr, ec] = std::from_chars(it, pctx.end(), index); ec == std::errc{}) {
it += (ptr - std::to_address(it));
pctx.check_arg_id(index);
} else {
index = next_arg_index;
pctx.next_arg_id();
++next_arg_index;
}
// オプション開始マークを解析する
if (it == pctx.end()) {
throw std::format_error("invalid format");
} else if (*it == ':') {
++it;
} else if (*it != '}') {
throw std::format_error("invalid format");
}
pctx.advance_to(it);
// フォーマッターを呼び出す
std::visit_format_arg(visitor, args.get(index));
// 置換フィールドの終端を解析する
if (it == pctx.end() || *it != '}') {
throw std::format_error("invalid format");
}
pctx.advance_to(++it);
continue;
}
} else if (*it == '}') {
++it;
if (it == pctx.end() || *it != '}') {
throw std::format_error("invalid format");
}
}
*out = *it;
pctx.advance_to(++it);
fctx.advance_to(++out);
}
return out;
}
```
* pctx.advance_to[link /reference/format/basic_format_parse_context/advance_to.md]
* fctx.advance_to[link /reference/format/basic_format_context/advance_to.md]
* formatter.parse[link /reference/format/formatter/parse.md]
* formatter.format[link /reference/format/formatter/format.md]
* std::format_error[link /reference/format/format_error.md]
* std::basic_format_parse_context[link /reference/format/basic_format_parse_context.md]
* std::basic_format_context[link /reference/format/basic_format_context.md]
* std::basic_format_args[link /reference/format/basic_format_args.md]
* std::visit_format_arg[link /reference/format/visit_format_arg.md]
* std::from_chars[link /reference/charconv/from_chars.md]

## バージョン
### 言語
- C++20
Expand Down

0 comments on commit 5398590

Please sign in to comment.