はじめに
C++で、数値や文字列を組み合わせて一つの整形された文字列を作成する際、従来はstringstream
やC言語由来のprintf
ファミリーが使われてきました。しかし、これらはコードが冗長になったり、型安全性が低かったりという問題がありました。
C++20では、これらの問題を解決する、モダンで強力な文字列フォーマットライブラリ <format>
が導入されました。その中心となるのが std::format
関数です。
この記事では、std::format
の基本的な使い方から、数値や文字列、コンテナに対する詳細な書式指定までを、網羅的に解説します。
【前提】C++20とは?
C++20は、2020年に正式化されたC++言語のメジャーアップデート版です。<format>
ライブラリはこのC++20で導入されたため、利用するにはC++20に対応したコンパイラが必要です。
1. 基本的な使い方
書式指定文字列の中の {}
(プレースホルダ)が、format
関数の後ろに続く引数に置き換えられます。
サンプルコード
#include <iostream>
#include <format> // format
#include <string>
using namespace std;
int main() {
// 引数の順番で自動的に置き換え
string s1 = format("{}, {}!", "Hello", "world");
cout << s1 << endl;
// インデックス(0始まり)で、引数の順番を指定・再利用できる
string s2 = format("{1} and {0}, {1}!", "Apple", "Banana");
cout << s2 << endl;
// {}自体を出力するには、{{}}と書く
string s3 = format("{{ C++20 }}");
cout << s3 << endl;
return 0;
}
2. 数値の書式指定
{}
の中にコロン :
を付けて、詳細な書式を指定できます。
サンプルコード
#include <iostream>
#include <format>
#include <numbers> // C++20の円周率定数
using namespace std;
int main() {
// --- 整数 ---
// 0埋め8桁の2進数で表示 (#でプレフィックス0bを付加)
cout << format("13の2進数: {:#08b}", 13) << endl; // -> 0b001101
// 0埋め4桁の16進数で表示 (#でプレフィックス0xを付加、大文字X)
cout << format("255の16進数: {:#04X}", 255) << endl; // -> 0xFF
// --- 浮動小数点数 ---
// 小数点以下3桁まで表示
cout << format("円周率 (小数点以下3桁): {:.3f}", numbers::pi) << endl;
// --- 符号 ---
// 常に符号(+)を表示、0埋め5桁
cout << format("符号付き: {:+05d}", 42) << endl; // -> +0042
// 正の数にはスペース、負の数には-を表示
cout << format("符号(スペース): {: d}", 42) << endl; // -> 42
return 0;
}
3. 文字列の書式指定
文字列の表示方法も制御できます。
サンプルコード
#include <iostream>
#include <format>
#include <string>
using namespace std;
int main() {
string text = "Hello\nWorld";
// 通常の出力
cout << format("通常: {}", text) << endl;
// デバッグ用の出力: クォートされ、エスケープシーケンスが表示される
cout << format("デバッグ用: {:?}", text) << endl;
return 0;
}
4. コンテナの書式指定
vector
やmap
などのコンテナも、{}
に入れるだけで簡単に出力できます。
サンプルコード
#include <iostream>
#include <format>
#include <vector>
#include <map>
#include <string>
using namespace std;
int main() {
vector<int> v = {10, 20, 30};
map<string, int> m = {{"apple", 1}, {"banana", 2}};
// vectorの出力
cout << format("vector: {}", v) << endl;
// mapの出力
cout << format("map: {}", m) << endl;
// コンテナの各要素に書式を適用
cout << format("vector(16進数): {::#x}", v) << endl;
return 0;
}
解説: {::#x}
のように、範囲フォーマット指定 ::
を使うと、コンテナの各要素に対して #x
(16進数プレフィックス付き)の書式が適用されます。
まとめ
今回は、C++20のstd::format
を使った、モダンで型安全な文字列フォーマットの方法を解説しました。printf
の柔軟性とstringstream
の型安全性を両立した、非常に強力な機能です。{}
プレースホルダと書式指定子を使いこなすことで、あらゆる出力要件に簡潔かつ安全に対応できます。