HOWTO · C++
C++ の STL コンテナーの value_type
STL は Standard Template Library の略です。 これは、C++ プログラミング言語の汎用コンテナーと関数を実装するために使用されるデータ構造とアルゴリズムのセットです。
このページの内容
STLコンテナーの value_type は、格納する要素の型を示す型エイリアスです。std::vector<int> では int、std::map<std::string, int> のような連想コンテナーではキーと値のペアが要素の型になります。このエイリアスはコンテナーの型を通じて指定でき、コンテナー型をテンプレート引数として受け取る汎用コードでも使えます。
value_typeの意味
コンテナーは、シーケンスやコレクションに含まれる各要素の型を示すために value_type を定義します。たとえば、std::vector<int>::value_type は int です。一方、mapの要素型はキーと対応する値を含むペアです。std::map<std::string, int> の場合、要素は std::pair で、その第1メンバーがキー、第2メンバーが対応する値です。格納されるペアでは、順序が保たれるようキーが const になります。このエイリアスを使うと、コンテナーを扱うコードで要素型を個別に書き直さずに参照できます。表すのは格納される要素1つの型であり、コンテナーオブジェクト自体の型ではありません。整数を格納するvectorの要素型は int ですが、vectorにはそれとは別のコンテナー型があります。
コンテナーのvalue_typeにアクセスする
スコープ演算子の前には、コンテナーの型を指定します。たとえば std::vector<int>::value_type です。これは型名なので、myVector がオブジェクトの場合、myVector::value_type とは書けません。要素型にローカルな名前を付けるには、using Element = std::vector<int>::value_type; と書けます。Container がテンプレート引数の場合にも Container::value_type という書き方を使います。この名前は依存型名なので、C++ではその前に typename が必要です。テンプレート宣言だけでは、依存名が型を指すのか値を指すのかコンパイラーが判断できないため、typename によって型であることを明示します。std::vector<int>::value_type のようにコンテナー型が具体的に決まっている通常のコードでは、コンパイラーがネストした型を認識できるため、この区別を示す必要はありません。
汎用コードでvalue_typeを使う
汎用関数では typename Container::value_type を使って要素型を指定できるため、異なるコンテナーを受け取れます。次の例はvectorとlistの各要素を出力します。出力される色ラベルの red と blue は、変更されていない例の中で英語のまま表示されます。
この例を実行します。
#include <iostream>
#include <list>
#include <string>
#include <vector>
template <typename Container>
void printElements(const Container& container) {
for (const typename Container::value_type& element : container) {
std::cout << element << '\n';
}
}
int main() {
const std::vector<int> numbers{1, 2, 3};
const std::list<std::string> colors{"red", "blue"};
printElements(numbers);
printElements(colors);
}
出力は次のとおりです。
1
2
3
red
blue
関数では、引数から Container が推論されるため、同じ本体を std::vector<int> と std::list<std::string> の両方で使えます。Container::value_type はそのテンプレート引数に依存するので、宣言では typename を付けています。ループは各要素をconst参照で受け取ります。要素をコピーせずに読み取れ、参照を通じてコンテナー内の要素を変更することはできません。この方法は、特定のコンテナーに依存せずに、ローカル変数、引数、戻り値の型として要素型を指定したい関数で役立ちます。ただし、コンテナーは関数が使う操作をサポートしている必要があります。この例で共通して必要なのは、範囲ベースfor文による反復処理です。
value_typeが行わないこと
value_type は要素型を示すものであり、メモリーの確保や解放は行いません。ストレージは、コンテナーとアロケーターがそれぞれの規則に従って扱います。また、このエイリアスによって、あるコンテナーが別のコンテナーより常に高速または安全になるわけではありません。ここでの実用上の利点は、汎用コードがユーザー定義の型も含め、各コンテナーが提供する要素型を指定できることです。value_type を持つすべてのコンテナーが同じインターフェイスを備えているという保証もありません。コードでは、受け入れるコンテナーがサポートする操作だけを使う必要があります。必要な操作や性能特性に基づいてコンテナーを選び、要素型もその選択に応じて決まるようにしたい場合に、そのエイリアスを使います。つまり、value_type は汎用コードに要素の型を伝えますが、コンテナーによる要素の格納方法や管理方法を決めるものではありません。