【C++】format() – C++でprintf()風の書式指定を使う

C++

はじめに

C++で値を出力するにはストリームを使いますが、桁数設定や小数点以下の精度表示をするためにわざわざsetw()setprecision()する必要があるなど、マニピュレータを使用した書式指定が面倒でした。

C言語に慣れているとprintf()の書式指定方法が便利で、printf()をC++でも使いたくなるときがあります。Boostライブラリには、似たようなものが用意されていますが、このためだけにBoostをインストールするのも大掛かりです。

しかしながら、ようやくC++20においてprinf()風の書式指定ができるformat()が標準仕様に追加されました。このエントリでは、このformat()についてまとめてみました。

使い方

format()関数はprintf()と同じような形で使うことができます。戻り値はstd::stringです。

std::format(書式指定を含む文字列, 値...)

{}でくくった部分を値で置き換えた文字列を作成します。書式指定は省略可能です。

  • int a = 0;
    std::string b = "test";
    std::string s = std::format("a = {}, b = {}", a, b); // "a = 0, b = test"

{}の中にprintf()のような書式指定を書くことができます。詳細な書式は以下になります。([]は省略可能の意味)

{[ID][:[[埋め文字]桁寄せ][符号][#][0][幅][.精度][L][種別]]}
種類説明
ID引数の番号。何番目の引数で置換するかを表す(0~)
埋め文字桁数指定したときの余白を埋める文字(省略時は空白)
桁寄せ右寄せ(>)、左寄せ(<)、中央揃え(^)を表す記号
符号プラス/マイナスを表示(+)、負の値でマイナスを表示(-)、正の値で空白を表示(スペース)
#代替表現を使用する(例:16進表示で"0x"を表示する)
00で埋める
表示幅
精度小数点以下の表示桁数
Lロケールを考慮する
種別値の表現方法

値の表現方法とは、整数を表すdや浮動小数点数を表すf、文字列を表すsなどのことです。以下のようなものが指定可能です。

種別意味
d整数
b2進数表示
o8進数表示
x16進数表示(小文字)
X16進数表示(大文字)
f実数(指数表示しない)
e実数(指数表示する)
g実数(必要に応じて指数表示する)
s文字列
c文字
pポインタ

使用例

実際にformat()を使った例を示します。printf()による書式指定方法と比較しました。

#include <cstdio>
#include <format>
#include <iostream>
#include <string>

using namespace std;

int main()
{
    int a = 10;
    float b = 3.1415926;
    unsigned char c = '\x20';
    char d[] = "string";

    // int型
    printf("%d\n", a);
    cout << format("{:d}", a) << endl;

    // int型、5桁出力、0埋め、+記号表示
    printf("%+05d\n", a);
    cout << format("{:+05d}", a) << endl;

    // float型、10桁出力、小数点以下5桁
    printf("%10.5f\n", b);
    cout << format("{:10.5f}", b) << endl;

    // float型、指数表記
    printf("%e\n", b);
    cout << format("{:e}", b) << endl;

    // unsigned char型、16進表示、2桁
    printf("%#02x\n", c);
    cout << format("{:#02x}", c) << endl;

    // 文字列、10桁出力、右揃え
    printf("%10s\n", d);
    cout << format("{:10s}", d) << endl;

    // 文字列、10桁出力、左揃え
    printf("%-10s\n", d);
    cout << format("{:<10s}", d) << endl;

    // 文字列、10桁出力、中央揃え: printf()ではできない
    cout << format("{:^10s}", d) << endl;

    // bool型
    cout << format("{}", true) << endl;
    cout << format("{}", false) << endl;

    return 0;
}

出力結果

10
10
+0010
+0010
   3.14159
   3.14159
3.141593e+00
3.141593e+00
0x20
0x20
    string
    string
string
string
  string
true
false

このように比較すると、%の代わりに:で始めることと{}でくくること以外は、printf()とほぼ同じ指定で使えることがわかると思います。

まとめ

C++20で導入されたprintf()風に使える関数format()についてまとめてみました。%の代わりに:で始めることと{}でくくること以外は、printf()とほぼ同じ指定で使えます。また、stringを返すのでprintf()sprintf()を使い分けるようなことが不要となります。

C++23以降ではさらに拡張され、vectormap, pairなどにも対応するようです。

(参考)

C++

Posted by izadori