待ちに待ったstd::format。そしてさらに!
C++ は元々「クラス付きのC言語」として開発されたのですが、C 言語はほぼそのまま C++ に含まれています。でも実際の C に比べると、C++ の中の C は少し使い方や挙動が違っていたりするため、注意しないといけないです。
それは置いといて、C++ には何に関しても、C のやり方と C++ のやり方があります。私は基本 C++ 派ですが、唯一自信を持って C++ の方をお勧めできないのが、出力関数です。
例えば以下のようなシンプルな出力の場合は、C++ の方が使いやすいです。
int ret = doSomething();
printf("doSomething() returned %d\n", ret); // Cスタイル
std::cout << "doSomething() returned " << ret << std::endl; // C++スタイル
-
printf
は改行を「\n
」のようにを文字として書かないといけなくて、変数の値を出力するために、「%d
」のようにその変数の型に該当する変換指定子を使わないといけないです。しかも、間違えて違う変換指定子を使ってしまうと、警告になりますがコンパイルエラーにならずに未定義動作が発生します。例えば、上記の例でret
はint
型なのにfloat
型の「%f
」を使ってしまうと、ret
が-1
の場合、「-1.000000
」ではなく「0.000000
」が出力されます。 -
std::cout
はstd::endl
のお陰で改行を文字として書かなくてもいいですし、int
やdouble
のような簡単な型は変換指定子なしで出力できます。
こういうシンプルな出力は std::cout
の方をお勧めできますが、もっと複雑な出力の場合はどうでしょうか?
const float number1 = 0.5f;
const int number2 = 1;
const std::string text = "text";
int ret = doSomething2(number1, number2, text);
printf("doSomething2(%f, %d, %s) returned %d\n", number1, number2, text.c_str(), ret);
std::cout << "doSomething2(" << number1 << ", " << number2 << ", " << text << ") returned " << ret << std::endl;
こちらはまだシンプルな出力なのに、急にstd::cout
の方がかなり読みづらくなりますね。
std::cout
は出力を左から右へ書いていくため、出力するメッセージの全体像が非常に見づらいです。途中のコンマや括弧閉じが抜けていても気づかない恐れがあります。
printf
の方が全体像が見えますが、変換指定子のせいで使いづらいため、昔は Boost ライブラリのboost::format
という関数を使っていました。
#include <boost/format.hpp>
std::cout << boost::format("doSomething2(%1%, %2%, %3%) returned %4%")
% number1 % number2 % text.c_str() % ret
<< std::endl;
でも C++20 からようやくboost::format
に似ているstd::format
という機能が追加されました!
std::format
を使うと、以下になります。
#include <format>
std::cout << std::format("doSomething2({}, {}, {}) returned {}", number1, number2, text, ret)
<< std::endl;
でもstd::format
はstd::string
を返すだけなので、実際の出力は別でしないといけないです。直接出力したい時は少し使いづらいです。
でも安心してください!printf
のように直接出力してくれる関数が C++23 で追加されます!
std::print("doSomething2({}, {}, {}) returned {}\n", number1, number2, text, ret);
std::println("doSomething2({}, {}, {}) returned {}", number1, number2, text, ret);
std::print
とstd::println
の違いは、std::println
は自動的に出力の最後に改行を入れてくれるということだけです。
これでようやく出力関数に関しても C より C++ の方が優れていると胸を張って言えるようになります!
Discussion