Q.std::begin
とかstd::data
って何のためにあるの?
A.テンプレート機能を利用してSTLコンテナ、固定長配列、初期化子リスト等に共通の機能を提供するため。
スコープと動作確認環境
- この記事ではC++20のStandard Template Library(STL)について扱います。
- サンプルコードの動作確認環境はWindows 10、Visual Studio Community 2019 Preview(Version 16.7.0 Preview 1.0)でC++言語標準をstd:c++latestとした状態です。
- 未確認ですがC++17も対応していると思います。
まえがき
STLはC++の標準ライブラリの一部であり、よく使う機能をクラスや関数テンプレートで提供する軽量なライブラリです。このノートではstd::begin
、std::data
等の目的と使い方を紹介します。個人的な目的は規格案やSTLの学習なので、不適切な部分があれば指摘いただけると嬉しいです。
イテレーターのRange access
概要
STLにはstd::begin
やstd::data
といったstd::vector
のクラス関数と同名の関数テンプレートが定義されています。これらはstd::vector
のようなSTLコンテナクラスだけ使用する場合は不要ですが、固定長配列(T x[N]
)や初期化子リスト(std::initializer_list
)に対して同様の機能を提供したい場合に役立ちます。
C++20規格案では23.7 Range accessに定義されています。
一覧
23.7 Range accessで定義されたイテレーターのRange accessの一覧です。以下の関数は関数テンプレートおよび特殊化によりSTLコンテナクラス、固定長配列、初期化子リストに対して使用できます。
関数 | 概要 |
---|---|
std::begin | 最初の要素 |
std::end | 最後の要素 |
std::cbegin | 最初の要素(const) |
std::cend | 最後の要素(const) |
std::rbegin | 末尾から最初の要素 |
std::rend | 末尾から最後の要素 |
std::crbegin | 末尾から最初の要素(const) |
std::crend | 末尾から最後の要素(const) |
std::size | 符号なしバイトサイズ |
std::ssize | 符号付きバイトサイズ |
std::empty | 空判定 |
std::data | 内部メモリのポインタ |
サンプルコード
次のコードでstd::cbegin
、std::data
、std::size
がSTLコンテナ、初期化子リスト、固定長配列に対して同様の機能を提供すること、std::list
のようなデータが不連続なSTLコンテナに対してはstd::data
が提供されないことを確認できます。
# include <iostream>
# include <string>
# include <list>
# include <vector>
// STLコンテナクラスを使用する場合はインクルードされるので不要です。
// #include <iterator>
int main()
{
std::wstring s = L"abcde";
std::vector<int> v = {0, 1, 2, 3, 4};
std::list<int> l = {0, 1, 2, 3, 4};
int a[5] = {0, 1, 2, 3, 4};
std::initializer_list<int> il = { 0, 1, 2, 3, 4 };
std::wcout << *std::cbegin(s) << std::endl; // 'a'
std::wcout << *std::cbegin(v) << std::endl; // 0
std::wcout << *std::cbegin(l) << std::endl; // 0
std::wcout << *std::cbegin(il) << std::endl;// 0
std::wcout << *std::cbegin(a) << std::endl; // 0
std::wcout << std::data(s) << std::endl; // "abcde" (<address>)
std::wcout << std::data(v) << std::endl; // <address>
// コメントを解除するとコンパイルエラー
// std::listはデータが連続しないのでstd::dataが適用できない。
// std::wcout << std::data(l) << std::endl;
std::wcout << std::data(a) << std::endl; // <address>
std::wcout << std::data(il) << std::endl;// <address>
std::wcout << std::size(s) << std::endl; // 5
std::wcout << std::size(v) << std::endl; // 5
std::wcout << std::size(l) << std::endl; // 5
std::wcout << std::size(a) << std::endl; // 5
std::wcout << std::size(il) << std::endl;// 5
return 0;
}
それぞれの定義を表示することでSTLコンテナ、固定長配列、初期化子リストに対して適切な関数テンプレートが呼び出されていることが分かります。