constexpr variant() noexcept(see below); // (1)
constexpr variant(const variant& other); // (2)
constexpr variant(variant&& other) noexcept(see below); // (3)
template <class T>
constexpr variant(T&& t) noexcept(see below); // (4)
template <class T, class... Args>
constexpr explicit variant(in_place_type_t<T>,
Args&&... args); // (5)
template <class T, class U, class... Args>
constexpr explicit variant(in_place_type_t<T>,
initializer_list<U> il,
Args&&... args); // (6)
template <size_t I, class... Args>
constexpr explicit variant(in_place_index_t<I>,
Args&&... args); // (7)
template <size_t I, class U, class... Args>
constexpr explicit variant(in_place_index_t<I>,
initializer_list<U> il,
Args&&... args); // (8)
概要
variant
オブジェクトを構築する。
- (1) : デフォルト構築。0番目の候補型の値を保持する
- (2) : コピーコンストラクタ
- (3) : ムーブコンストラクタ
- (4) : 候補型のいずれかの型の値を保持する
- (5) : 候補型のうち、指定した型のコンストラクタ引数を受け取ってコンストラクタ内でそのオブジェクトを構築して保持する
- (6) : 候補型のうち、指定した型のコンストラクタ引数
il
とargs...
を受け取ってコンストラクタ内でそのオブジェクトを構築して保持する - (7) : 候補型のうち、指定したインデックスの型のコンストラクタ引数を受け取ってコンストラクタ内でそのオブジェクトを構築して保持する
- (8) : 候補型のうち、指定したインデックスの型のコンストラクタ引数
il
とargs...
を受け取ってコンストラクタ内でそのオブジェクトを構築して保持する
テンプレートパラメータ制約
- 候補型
Types...
のi番目の型をTi
とする - (1) :
is_default_constructible_v<T0>
であること
- (2) :
- 全ての型
Ti
について、is_copy_constructible_v<Ti>
がtrue
であること
- 全ての型
- (3) :
- 全ての型
Ti
について、is_move_constructible_v<Ti>
がtrue
であること
- 全ての型
- (4) :
- C++17 : ここで説明用に、
*this
が保持している型Tj
と、そのインデックス値j
を定義する。Types...
の各型Ti
に対して擬似的な関数FUN(Ti)
を定義したとして、FUN(std::forward<T>(t))
呼び出しによって選択されたオーバーロードされた関数のパラメータ型を、構築してその後含まれる値の型をTj
とする - C++20 : ここで説明用に、
*this
が保持している型Tj
と、そのインデックス値j
を定義する。Types...
の各型Ti
を、縮小変換を受け付けない型であり (Ti x[] = {std::forward<T>(t)};
)、CV修飾付きbool
の場合にCV修飾を外したbool
型になるとして、その型に対して擬似的な関数FUN(Ti)
を定義したとして、FUN(std::forward<T>(t))
呼び出しによって選択されたオーバーロードされた関数のパラメータ型を、構築してその後含まれる値の型をTj
とする - C++17 :
is_same_v<decay_t<T>, variant>
がfalse
であること - C++20 :
is_same_v<remove_cvref_t<T>, variant>
がfalse
であること - C++17 : 型
decay_t<T>
がin_place_type_t
およびin_place_index_t
の特殊化ではないこと - C++20 : 型
remove_cvref_t<T>
がin_place_type_t
およびin_place_index_t
の特殊化ではないこと -is_constructible_v<Tj, T>
がtrue
であること - 式
FUN(std::forward<T>(x))
が適格であること
- C++17 : ここで説明用に、
- (5) :
Types...
内にT
が一度だけ現れることis_constructible_v<T, Args...>
がtrue
であること
- (6) :
Types...
内にT
が一度だけ現れることis_constructible_v<T, initializer_list<U>&, Args...>
がtrue
であること
- (7) :
Types...
のI
番目の型をTi
とするI < sizeof...(Types)
であることis_constructible_v<Ti, Args...>
がtrue
であること
- (8) :
Types...
のI
番目の型をTi
とするI < sizeof...(Types)
であることis_constructible_v<Ti, initializer_list<U>&, Args...>
がtrue
であること
効果
- (1) :
T0
型を値初期化して保持する
- (2) :
- (3) :
- (4) :
std::forward<T>(t)
によってTj
型を直接構築して*this
に保持する
- (5) :
std::forward<Args>(args)...
をコンストラクタ引数としてT
型オブジェクトを直接構築して*this
に保持する
- (6) :
il
とstd::forward<Args>(args)...
をコンストラクタ引数としてT
型オブジェクトを直接構築して*this
に保持する
- (7) :
std::forward<Args>(args)...
をコンストラクタ引数としてTi
型オブジェクトを直接構築して*this
に保持する
- (8) :
il
とstd::forward<Args>(args)...
をコンストラクタ引数としてTi
型オブジェクトを直接構築して*this
に保持する
事後条件
- (1) :
valueless_by_exception()
がfalse
であることindex()
が0
であること
- (4) :
std::holds_alternative<Tj>(*this)
がtrue
であること
- (5), (6) :
std::holds_alternative<T>(*this)
がtrue
であること
- (7), (8) :
index()
がI
であること
例外
- (1) :
T0
型を値初期化した際、その型のコンストラクタによって任意の例外が送出される可能性があるnoexcept
内の式は、is_nothrow_default_constructible_v<T0>
と等価
- (2) :
- 全ての型
Ti
の直接初期化が、任意の例外を送出する可能性がある
- 全ての型
- (3) :
- 全ての型
Ti
のムーブ構築が、任意の例外を送出する可能性がある noexcept
内の式は、全てのTi
についてのis_nothrow_move_constructible_v<Ti>
を論理積したものと等価
- 全ての型
- (4) :
Tj
の選択された初期化方法 (コンストラクタ) が任意の例外を送出する可能性があるnoexcept
内の式は、is_nothrow_constructible_v<Tj, T>
と等価となる
- (5), (6) :
- 型
T
の選択されたコンストラクタが任意の例外を送出する可能性がある
- 型
- (7), (8) :
- 型
Ti
の選択されたコンストラクタが任意の例外を送出する可能性がある
- 型
トリビアルに定義される条件
- (2) : 全ての
Ti
型について、is_trivially_copy_constructible_v<Ti>
がtrue
であること - (3) : 全ての
Ti
型について、is_trivially_move_constructible_v<Ti>
がtrue
であること
定数式に評価される条件
- (1) :
T0
型の値初期化がconstexpr
関数の要件を満たすこと - (4) : 型
Tj
の選択された初期化方法 (コンストラクタ) がconstexpr
評価できること - (5), (6) : 型
T
の選択されたコンストラクタがconstexpr
評価できること - (7), (8) : 型
Ti
の選択されたコンストラクタがconstexpr
評価できること
備考
- (4) : 以下のコードは不適格となる。第1テンプレート引数の型をとるコンストラクタオーバーロードと、第2テンプレート引数の型をとるコンストラクタオーバーロードが定義されるため、曖昧になる:
std::variant<std::string, std::string> v("abc"); // コンパイルエラー!
例
基本的な使い方
#include <cassert>
#include <variant>
#include <string>
int main()
{
// (1)
// デフォルト構築
{
// 0番目の型 (ここではint) が値初期化される
std::variant<int, char, double> v;
assert(v.index() == 0);
assert(std::holds_alternative<int>(v));
assert(std::get<int>(v) == 0); // 値初期化されるのでゼロ初期化される (不定値にはならない)
}
// (2)
// コピー構築
{
std::variant<int, char, double> a = 1;
std::variant<int, char, double> b = a;
assert(a == b);
assert(std::holds_alternative<int>(a));
assert(std::holds_alternative<int>(b));
}
// (3)
// ムーブ構築
{
std::variant<int, char, double> a = 1;
std::variant<int, char, double> b = std::move(a);
assert(std::holds_alternative<int>(b));
assert(std::get<int>(b) == 1);
}
// (4)
// 候補型のうち、いずれかの型の値を代入
{
std::variant<int, char, double> v = 3.14;
assert(std::holds_alternative<double>(v));
assert(std::get<double>(v) == 3.14);
}
// (5)
// 候補型のうち、いずれかの型のコンストラクタ引数をとって、
// コンストラクタ内でその型のオブジェクトを構築して保持する
{
// コンストラクタ引数3と'a'を渡して、
// コンストラクタ内でstd::string型オブジェクトを構築する
std::variant<int, char, std::string> v{
std::in_place_type<std::string>,
3,
'a'
};
assert(std::holds_alternative<std::string>(v));
assert(std::get<std::string>(v) == "aaa");
}
// (6)
// (5) とほぼ同じ。コンストラクタ引数の先頭が初期化子リストの場合に、
// こちらが呼ばれる。
{
std::allocator<char> alloc;
std::variant<int, char, std::string> v{
std::in_place_type<std::string>,
{'H', 'e', 'l', 'l', 'o'},
alloc
};
assert(std::holds_alternative<std::string>(v));
assert(std::get<std::string>(v) == "Hello");
}
// (7)
// 候補型のうち、I番目の型のコンストラクタ引数をとって、
// コンストラクタ内でその型のオブジェクトを構築して保持する
{
// コンストラクタ引数3と'a'を渡して、
// コンストラクタ内で2番目の型 (std::string) のオブジェクトを構築する
std::variant<int, char, std::string> v{
std::in_place_index<2>,
3,
'a'
};
assert(v.index() == 2);
assert(std::holds_alternative<std::string>(v));
assert(std::get<std::string>(v) == "aaa");
}
// (7)
// (6) とほぼ同じ。コンストラクタ引数の先頭が初期化子リストの場合に、
// こちらが呼ばれる。
{
// コンストラクタ引数3と'a'を渡して、
// コンストラクタ内で2番目の型 (std::string) のオブジェクトを構築する
std::allocator<char> alloc;
std::variant<int, char, std::string> v{
std::in_place_index<2>,
{'H', 'e', 'l', 'l', 'o'},
alloc
};
assert(v.index() == 2);
assert(std::holds_alternative<std::string>(v));
assert(std::get<std::string>(v) == "Hello");
}
}
出力
あいまいになりそうな代入の例 (C++20)
#include <cassert>
#include <variant>
#include <string>
int main()
{
// 縮小変換 (narrowing conversion) は行われないので、
// 0がfloat型に代入されたりはしない
{
std::variant<float, int> v = 0;
assert(std::holds_alternative<int>(v));
}
{
// 文字列リテラルは、C++17ではstd::stringよりもboolに優先的に変換されてしまう
std::variant<std::string, bool> v = "abc";
assert(std::holds_alternative<std::string>(v)); // C++17ではbool、C++20ではstd::string
std::variant<std::string> v2 = "abc";
assert(std::holds_alternative<std::string>(v2));
std::variant<std::string, bool> v3 = std::string("abc"); // C++17/C++20でstd::string
assert(std::holds_alternative<std::string>(v3));
}
}
出力
同じ型を複数指定できる状況の例
#include <cassert>
#include <variant>
#include <string>
int main()
{
// インデックスを指定した代入なら、同じ型が複数現れてもよい。
// 代入演算子、emplace<T>()、std::get<T>()、std::holds_alternative<T>()は使用できない。
// emplace<I>()、std::get<I>(), index()は使用できる
std::variant<std::string, std::string> v1 { // OK
std::in_place_index<0>,
"abc"
};
std::string& s = std::get<0>(v1);
assert(s == "abc");
//std::variant<std::string, std::string> v2 { // コンパイルエラー!
// std::in_place_type<std::string>,
// "abc"
//};
//std::variant<std::string, std::string> v3 = "abc"; // コンパイルエラー!
}
出力
バージョン
言語
- C++17
処理系
- Clang: 4.0.1
- GCC: 7.3
- Visual C++: ??