class template
std::variant(C++17)
namespace std {
template <class... Types>
class variant;
}
概要
variant
クラスは、格納されうる候補の型リスト (Types...
) に含まれる型のオブジェクトを切り替えながら保持する記憶域型である。継承関係にない複数の型を、単一のオブジェクトに代入・切り替えができる。
これは、継承によって基底クラスのオブジェクトに派生クラスのオブジェクトを代入できることと同様に、候補として列挙した複数の型のオブジェクトを単一の型のオブジェクトに代入して扱えるという点で、多態性を表現している。インタフェースが異なる複数の型の場合はビジター関数オブジェクトによって型ごとの動作を定義でき、インタフェースが共通の型の場合は、関数テンプレートの関数呼び出し演算子をもつ関数オブジェクトをビジターにすることで共通の動作をさせることができる。
// 継承関係にないクラス群
struct A { void f() {} };
struct B { void f() {} };
struct C { void f() {} };
// A, B, Cのいずれかの型を代入できる型
std::variant<A, B, C> v = A{}; // A型のオブジェクトを代入
v = B{}; // B型のオブジェクトに切り替え
// B型オブジェクトを保持しているか
if (std::holds_alternative<B>(v)) {
// 保持しているB型オブジェクトを取得
B& b = std::get<B>(v);
}
// どの型が代入されていたとしても、共通のインタフェースを呼び出す
std::visit([](auto& x) {
x.f();
}, v);
このクラスと同様のことは共用体を使用しても達成できるが、このクラスはより使いやすいよう設計されている。
このクラスは追加の動的メモリ確保は行わず、保持するオブジェクトを自身のオブジェクト表現内に直接割り当てる。
備考
- このクラスはBoost Variant Libraryを元に設計されている
- Boost Variant Libraryは、recursive variantによって再帰的なデータ構造を扱えるが、現時点の
std::variant
クラスではそのようなデータ構造は扱えない
- これは、JSONデータ形式のように値として数値・文字列・配列などを設定でき、配列の要素にもまた数値・文字列・配列などを設定できる、というようなデータの読み込み、書き込みで必要となる
- Boost Variant Libraryは、「決して空にならない保証 ("Never-Empty" Guarantee)」を提供しており、たとえ代入中に例外が発生したとしても、候補型のいずれの型も代入されていない状況が起こらないよう設計・実装されていた。標準ライブラリに導入されたこのクラスは、代入中に例外が発生した場合に空になる可能性をもっている
- このクラスは、他の言語で「代数データ型 (Algebraic data type)」「直和型 (Union type, Sum type)」「タグ付き共用体 (Tagged union)」と呼ばれる機能の一部を表現できる。また、
Either
型として近しい機能が提供されている場合もある
Types...
の全ての型が、std::destructible
要件を満たすこと
- コンストラクタや代入の制約として、
variant<std::string, std::string>
のように、Types...
内に同じ型が複数回現れる指定をする場合は、型のインデックスを指定する形式の機能のみ使用できる
- こういった指定は、正常データかエラーデータどちらかが代入されるオブジェクトを用意する状況で、正常データとエラーデータがどちらも文字列、という場合に必要になる
メンバ関数
構築・破棄
代入
名前 |
説明 |
対応バージョン |
operator= |
代入演算子 |
C++17 |
emplace |
要素型のコンストラクタ引数から直接構築する |
C++17 |
swap |
他のvariant オブジェクトとデータを入れ替える |
C++17 |
値の観測
非メンバ関数
値の取得
名前 |
説明 |
対応バージョン |
get |
保持している値を取得する |
C++17 |
get_if |
保持している値を指すポインタを取得する。エラー時にヌルポインタを返す |
C++17 |
ビジター
名前 |
説明 |
対応バージョン |
visit |
variant オブジェクトが現在保持している型に対応する関数を呼び出す |
C++17 |
値の入れ替え
名前 |
説明 |
対応バージョン |
swap |
2つのvariant オブジェクトを入れ替える |
C++17 |
比較演算子
ハッシュサポート
名前 |
説明 |
対応バージョン |
template <class T> struct hash; |
hash クラスの先行宣言 |
C++17 |
template <class ...Types> struct hash<variant<Types...>>; |
hash クラスのvariant に対する特殊化 |
C++17 |
アロケータインタフェース
名前 |
説明 |
対応バージョン |
template <class T, class Alloc> struct uses_allocator; |
uses_allocator クラスの先行宣言 |
C++17 |
template <class... Types, class Alloc> struct uses_allocator<variant<Types...>, Alloc>; |
uses_allocator クラスのvariant に対する特殊化 |
C++17 |
例
出力
3
Hello
バージョン
言語
処理系
参照