C++教科書/標準ライブラリ編/<print>の章
編集はじめに
編集この章では、C++23で導入された新しい入出力ライブラリヘッダーである<print>
について説明します。<print>
ヘッダーは、フォーマット指定子を使用した柔軟な出力機能を提供します。
機能
編集<print>
ヘッダーは以下の主要な機能を提供します。
std::print
関数: フォーマット指定子と可変個引数を使用して、標準出力 (stdout) またはファイルストリームに出力します。std::println
関数:std::print
関数と同様ですが、各出力の後に改行文字 (\n
) を追加します。std::vprint
関数群: タイプ情報を消去した引数表現を使用して、出力を行います。Unicode 対応の入出力ストリームとそうでないストリーム向けの関数があります。
関数の詳細
編集この節では、各関数の詳細について説明します。
print 関数
編集std::print
関数は、最も基本的な出力関数です。フォーマット指定子と可変個の引数を受け取り、フォーマットに従って引数を整形した結果を出力先に送ります。出力先は、標準出力 (stdout) または FILE
オブジェクトを指定できます。
構文
編集template <class... Args> void print(format_string<Args...> fmt, Args&&... args); template <class... Args> void print(FILE* stream, format_string<Args...> fmt, Args&&... args);
引数
編集fmt
: フォーマット指定子オブジェクト。std::format
ヘッダーで定義された型である必要があります。args
: 可変個の引数。フォーマット指定子で指定されたプレースホルダーと一致する型である必要があります。stream
: 出力先となるFILE
オブジェクト。省略すると、標準出力 (stdout) になります。
戻り値
編集なし
- 例
#include <print> int main() { int age = 30; std::string name = "太郎"; std::print("名前: ", name, ", 年齢: ", age, "\n"); return 0; }
println 関数
編集std::println
関数は、std::print
関数と同様ですが、出力の最後に改行文字 (\n
) を追加します。単独で呼び出すこともでき、この場合、空の文字列が出力されます。
構文
編集template <class... Args> void println(format_string<Args...> fmt, Args&&... args); void println(); template <class... Args> void println(FILE* stream, format_string<Args...> fmt, Args&&... args); void println(FILE* stream);
引数
編集fmt
: フォーマット指定子オブジェクト。std::format
ヘッダーで定義された型である必要があります。省略すると、空の文字列になります。args
: 可変個の引数。フォーマット指定子で指定されたプレースホルダーと一致する型である必要があります。省略すると、引数は渡されません。stream
: 出力先となるFILE
オブジェクト。省略すると、標準出力 (stdout) になります。
戻り値
編集なし
- 例
#include <print> int main() { std::println("Hello, World!"); std::println("年齢は", 30, "歳です。"); return 0; }
vprint 関数群
編集std::vprint
関数群は、可変個引数を受け取り、その型の情報を消去してから出力を行います。これにより、テンプレート化を簡略化したり、可変長の引数パックを処理しやすくなります。Unicode 対応の入出力ストリーム向けの vprint_unicode
関数と、そうでないストリーム向けの vprint_nonunicode
関数が用意されています。どちらの関数も、フォーマット文字列と可変長引数パックを受け取ります。
概要
編集std::vprint
関数群で使用されるフォーマット文字列は、std::format
ヘッダーで定義された string_view
型の文字列です。この文字列には、出力するデータの形式を指定するためのプレースホルダーが含まれます。プレースホルダーは、{}
などのブレイスタイプ記号で囲まれます。
プレースホルダーの種類
編集std::vprint
関数群で使用できるプレースホルダーには、以下の種類があります。
- 整数プレースホルダー:
{}
- 浮動小数点プレースホルダー:
{:.nf}
- 文字列プレースホルダー:
{:[flags][width][.precision]}s
- ポインタプレースホルダー:
{:[flags][width][.precision]}p
- カスタムフォーマタープレースホルダー:
{:[flags][width][.precision]}fmt
プレースホルダーの詳細
編集- 整数プレースホルダー
{}
プレースホルダーは、整数値を出力します。- 例
std::vprint_unicode("数値: {}\n", std::make_format_args(100));
- 出力結果
数値: 100
- 浮動小数点プレースホルダー
{:.nf}
プレースホルダーは、浮動小数点値を出力します。n
は精度を指定する整数で、.
の後に指定します。- 例
std::vprint_unicode("小数: {:.2f}\n", std::make_format_args(3.14159265));
- 出力結果
小数: 3.14
- 文字列プレースホルダー
{:[flags][width][.precision]}s
プレースホルダーは、文字列を出力します。[flags]
: 出力形式を設定するフラグ。省略できます。-
: 左寄せ+
: 正号を常に表示- : 空白を常に表示
[width]
: 出力幅を設定する整数。省略できます。[.precision]
: 出力する文字数または有効桁数を設定する整数。省略できます。
- 例
std::string name = "太郎"; std::vprint_unicode("名前: {:-10}さん\n", std::make_format_args(name));
- 出力結果
名前: 太郎 さん
- ポインタプレースホルダー
{:[flags][width][.precision]}p
プレースホルダーは、ポインタ値を出力します。- *
[flags]
: 出力形式を設定するフラグ。省略できます。 - **
#
: 0x を接頭辞として付加 - *
[width]
: 出力幅を設定する整数。省略できます。 - *
[.precision]
: 出力する桁数を設定する整数。省略できます。 - 例
int num = 100; std::vprint_unicode("ポインタ: {#:x}\n", std::make_format_args(&num));
- 出力結果
ポインタ: 0x64
- カスタムフォーマタープレースホルダー
{:[flags][width][.precision]}fmt
プレースホルダーは、カスタムフォーマターを使用してデータを出力します。[flags]
: 出力形式を設定するフラグ。省略できます。-
: 左寄せ+
: 正号を常に表示- : 空白を常に表示
[width]
: 出力幅を設定する整数。省略できます。[.precision]
: 出力する文字数または有効桁数を設定する整数。省略できます。fmt
: カスタムフォーマターを指定する文字列。
- 例
struct Person { std::string name; int age; }; Person p{"太郎", 30}; std::vprint_unicode("名前: {}, 年齢: {}\n", std::make_format_args(p, [](const Person& p) { return std::make_tuple(p.name, p.age); }));
- 出力結果
名前: 太郎, 年齢: 30
- まとめ
std::vprint
関数群で使用されるフォーマット文字列は、出力するデータの形式を柔軟に指定することができます。
vprint_unicode 関数群
編集- 構文
void vprint_unicode(string_view fmt, format_args args); void vprint_unicode(FILE* stream, string_view fmt, format_args args); void vprint_unicode_locking(FILE* stream, string_view fmt, format_args args);
- 引数
-
fmt
: フォーマット文字列。std::format
ヘッダーで定義されたstring_view
型である必要があります。args
: 可変長引数パック。std::format
ヘッダーで定義されたformat_args
型である必要があります。stream
: 出力先となるFILE
オブジェクト。省略すると、標準出力 (stdout) になります。
- 戻り値
- なし
- 例
#include <print> int main() { std::string_view fmt = "名前: {}, 年齢: {}\n"; std::string name = "太郎"; int age = 30; std::vprint_unicode(fmt, std::make_format_args(name, age)); return 0; }
vprint_nonunicode 関数群
編集- 構文
void vprint_nonunicode(string_view fmt, format_args args); void vprint_nonunicode(FILE* stream, string_view fmt, format_args args); void vprint_nonunicode_locking(FILE* stream, string_view fmt, format_args args);
- 引数
-
fmt
: フォーマット文字列。std::format
ヘッダーで定義されたstring_view
型である必要があります。args
: 可変長引数パック。std::format
ヘッダーで定義されたformat_args
型である必要があります。stream
: 出力先となるFILE
オブジェクト。省略すると、標準出力 (stdout) になります。
- 戻り値
- なし
- 例
#include <print> int main() { std::string_view fmt = "名前: {}, 年齢: {}\n"; std::string name = "太郎"; int age = 30; std::vprint_nonunicode(fmt, std::make_format_args(name, age)); return 0; }
<print>
ヘッダーの導入は、C++の使いやすさを向上させ、他の言語からの移行を容易にするための一環として考えられています。特に、PythonやRustなどのモダンなプログラミング言語で見られるシンプルで強力なフォーマット機能に触発されています。
以下に、その具体的な背景と利点について説明します。
- 背景
- 他の言語と比較すると、C++の標準ライブラリで提供される出力機能(
std::cout
など)は強力ですが、やや冗長で使いにくい部分がありました。例えば、複数の変数を一行で出力する場合、std::cout
を使用すると以下のように書く必要があります。 #include <iostream> int main() { int x = 10; double y = 20.5; std::cout << "The value of x is " << x << " and the value of y is " << y << std::endl; return 0; }
- これに対し、Pythonのような言語ではフォーマット文字列を使用することでより簡潔に書くことができます。
x = 10 y = 20.5 print(f"The value of x is {x} and the value of y is {y}")
- この違いを埋めるために、C++23では
<print>
ヘッダーが導入されました。 <print>
の利点-
- 簡潔さと読みやすさ
#include <print> int main() { int x = 10; double y = 20.5; std::print("The value of x is {} and the value of y is {}\n", x, y); return 0; }
- フォーマットされた文字列を使用することで、コードが簡潔になり、読みやすさが向上します。
- 他言語との類似性
- C++23の
<print>
は、Pythonのprint
関数やRustのprintln!
マクロと似た構文を採用しており、これらの言語からC++への移行をスムーズにします。 - Python
print(f"The value of x is {x} and the value of y is {y}")
- Rust
println!("The value of x is {} and the value of y is {}", x, y);
- 統一されたインターフェース
- 従来の
std::cout
に比べて、std::print
は一貫性のあるインターフェースを提供し、エラーが少なく、直感的に使いやすいです。 - フォーマットの柔軟性
- 変数のフォーマット方法を簡単にカスタマイズできます。例えば、小数点以下の桁数を指定するなどの操作が容易です。
- 結論
- C++23の
<print>
ヘッダーは、他のモダンなプログラミング言語からの移行を容易にし、C++の使いやすさを向上させるための重要なステップです。これにより、C++の学習曲線が緩和され、他の言語からの移行者や新規学習者にとって魅力的な選択肢となるでしょう。
まとめ
編集<print>
ヘッダーは、フォーマット指定子を使用した柔軟な出力機能を提供します。std::print
関数、std::println
関数、std::vprint
関数群の使い分けを理解することで、様々な出力形式に対応することができます。
参考文献
編集- C++ - Standards. ISO/IEC. (2024-01-17) .
- Working Draft Programming Languages — C++. ISO/IEC. (2024/04/16) .