namespace std {
template <class T, class charT = char>
struct formatter; // (1) C++20
template <ranges::input_range R, class charT>
requires (format_kind<R> != range_format::disabled) &&
formattable<ranges::range_reference_t<R>, charT>
struct formatter<R, charT>
: range-default-formatter<format_kind<R>, R, charT> { }; // (2) C++23
template <class charT, formattable<charT>... Ts>
struct formatter<pair-or-tuple<Ts...>, charT>; // (3) C++23
template <class charT,
class T,
formattable<charT> Container,
class... U>
struct formatter<adaptor-type<T, Container, U...>, charT>; // (4) C++23
}
概要
フォーマット引数の個々の型に対応する書式文字列の解析と値のフォーマットを担うクラス。
- (1) : デフォルトのフォーマット
- (2) : Range用のフォーマット。実装は
range-default-formatter
クラスが行う - (3) :
std::pair
とstd::tuple
に対する特殊化 - (4) : コンテナアダプタである
std::queue
、std::priority_queue
、std::stack
に対する特殊化
(1)は、charT
をchar
またはwchar_t
とすると、標準で以下の特殊化が利用できる。
template<> struct formatter<charT, charT>
template<> struct formatter<char, wchar_t>
template<> struct formatter<charT*, charT>
template<> struct formatter<const charT*, charT>
template<size_t N> struct formatter<const charT[N], charT>
template<class traits, class Allocator> struct formatter<basic_string<charT, traits, Allocator>, charT>
template<class traits> struct formatter<basic_string_view<charT, traits>, charT>
- 第1テンプレート引数が
nullptr_t
,void*
,const void*
,bool
, すべてのCV修飾されない標準の整数型, 拡張整数型, 浮動小数点数型であり、第2テンプレート引数がcharT
であるもの。
さらに、ユーザーがformatter
を特殊化した場合、それも有効である。
標準でもユーザー定義でも特殊化されない場合、その型に対するformatter
は無効であり、そのような型はフォーマット関数の引数にできない。
ワイド文字列とマルチバイト文字列を相互に変換するような特殊化は意図的に用意されていないが、ユーザーが用意することは禁止していない。
ユーザーの型でformatter
を特殊化する場合の要件
formatter
の有効な特殊化はFormatter要件を満たす必要がある。
型F
がFormatter要件を満たすとは、次のことをいう。
F
はCpp17DefaultConstructible
、Cpp17CopyConstructible
、Cpp17CopyAssignable
、Cpp17Destructible
であること
さらに、以下の条件を満たすこと
- 式
f.parse(pc)
が有効であり、- 戻り値の型が
PC::iterator
である - イテレータ範囲
[pc.begin(), pc.end())
を解析してformat_error
を投げるか、解析が終わった位置を指すイテレータを返す
- 戻り値の型が
- 式
cf.format(t, fc)
が有効であり、- 戻り値の型が
FC::iterator
である - フォーマット結果を
fc.out()
へ出力し、出力後のイテレータを返す - 出力は
t
、fc.locale()
、最後に呼び出されたf.parse(pc)
のイテレータ範囲[pc.begin(), pc.end())
以外に依存しない
- 戻り値の型が
- 式
cf.format(u, fc)
が有効であり、- 戻り値が
FC::iterator
である - フォーマット結果を
fc.out()
へ出力し、出力後のイテレータを返す - 出力は
u
、fc.locale()
、最後に呼び出されたf.parse(pc)
のイテレータ範囲[pc.begin(), pc.end())
以外に依存しない u
を変更しない
- 戻り値が
条件内の各要素を、以下のように定義する。
- 文字の型を
charT
- 出力イテレータの型を
Out
- フォーマット引数の型を
T
f
をF
のオブジェクトcf
をF
のconst
オブジェクトu
をT
のlvaluet
をT
またはconst T
へ変換できる型のオブジェクトPC
をbasic_format_parse_context<charT>
FC
をbasic_format_context<Out, charT>
pc
をPC
のlvaluefc
をFC
のlvalue
ただし、parse
の呼び出し前の状態で、pc.begin()
は書式文字列中の対応する置換フィールドのオプションの先頭を指す。
- オプションが空でなければ、
*pc.begin()
は:
の次の文字 - オプションが空なら、
pc.begin() == pc.end()
または*pc.begin() == '}'
である
std::formattable
コンセプトも参照。
フォーマッターは、書式文字列中に置換フィールドが見つかるたびに次のコードと近い形で呼び出される。
typename FC::template formatter_type<T> f;
pc.advance_to(f.parse(pc)); // オプションを解析し状態を保存する
fc.advance_to(f.format(u, fc)); // 状態をもとにフォーマットを行う
handleも参照。
メンバ関数
メンバ関数 | 説明 | 対応バージョン |
---|---|---|
parse |
書式の解析を行う | C++20 |
format |
書式化を行う | C++20 |
文字・文字列に対する特殊化
メンバ関数 | 説明 | 対応バージョン |
---|---|---|
set_debug_format |
デバッグ出力を有効にする | C++23 |
pair / tuple向けの特殊化
メンバ関数 | 説明 | 対応バージョン |
---|---|---|
set_separator |
要素の区切り文字を設定する | C++23 |
set_brackets |
全体の囲み文字を設定する | C++23 |
例
オリジナル書式なし、型変換のみの場合
#include <iostream>
#include <format>
enum color { red, green, blue };
const char* color_names[] = { "red", "green", "blue" };
template<>
struct std::formatter<color> : std::formatter<const char*> {
auto format(color c, std::format_context& ctx) const {
return std::formatter<const char*>::format(color_names[c], ctx);
}
};
int main()
{
std::cout << std::format("{}", red) << std::endl;
}
出力
red
オリジナル書式を定義する例
#include <iostream>
#include <format>
enum color { red, green, blue };
const char* color_names[] = { "red", "green", "blue" };
const char* jp_color_names[] = { "赤", "緑", "青" };
template<>
struct std::formatter<color> {
bool is_jp = false;
// コンパイル時の書式文字列の解析があるため、
// constexprにする必要がある。
// この関数に渡されるパラメータは、{:%j}の%以降。
// 解析がおわった場所を指すイテレータを返す。
constexpr auto parse(std::format_parse_context& ctx) {
auto it = ctx.begin();
if (*it == '%') {
++it;
if (*it == 'j') {
is_jp = true;
}
else if (*it == 'e') {
is_jp = false;
}
++it;
}
return it;
}
// format()関数は書式の情報をもたない。
// parse()関数で解析した書式をメンバ変数で保持しておいて、
// それをもとに書式化する
auto format(color c, std::format_context& ctx) const {
return std::format_to(ctx.out(), "{}",
is_jp ? jp_color_names[c] : color_names[c]
);
}
};
int main()
{
std::cout << std::format("{:%j} {:%e}", red, blue) << std::endl;
}
出力
赤 blue
複数のメンバ変数を含むクラスの場合
#include <iostream>
#include <format>
struct Point {
float x, y;
};
template<>
struct std::formatter<Point> : std::formatter<std::string> {
auto format(Point p, std::format_context& ctx) const {
return std::formatter<std::string>::format(
std::format("[{}, {}]", p.x, p.y),
ctx);
}
};
int main()
{
std::cout << std::format("{}", Point{1.2f, 3.4f}) << std::endl;
}
出力
[1.2, 3.4]
バージョン
言語
- C++20
処理系
- Clang: 17 ✅
- GCC: 13 ✅
- Visual C++: 2022 Update 2 ✅
関連項目
参照
- P0645R10 Text Formatting
- {fmt}
- P2286R8 Formatting Ranges
- P2585R1 Improve default container formatting
- C++23から、Range・コンテナ、
pair
、tuple
のフォーマット出力、および文字・文字列のデバッグ指定 ("?"
) が追加された
- C++23から、Range・コンテナ、