std::variant<Types...>:: variant
|
constexpr
variant
(
)
noexcept
(
/* 见下文 */
)
;
|
(1) | (C++17 起) |
|
constexpr
variant
(
const
variant
&
other
)
;
|
(2) | (C++17 起) |
|
constexpr
variant
(
variant
&&
other
)
noexcept
(
/* 见下文 */
)
;
|
(3) | (C++17 起) |
|
template
<
class
T
>
constexpr variant ( T && t ) noexcept ( /* 见下文 */ ) ; |
(4) | (C++17 起) |
|
template
<
class
T,
class
...
Args
>
|
(5) | (C++17 起) |
|
template
<
class
T,
class
U,
|
(6) | (C++17 起) |
|
template
<
std::
size_t
I,
class
...
Args
>
|
(7) | (C++17 起) |
|
template
<
std::
size_t
I,
class
U,
|
(8) | (C++17 起) |
构造一个新的
variant
对象。
variant
(此时
index()
为零)。
-
当且仅当可选类型
T_0的值初始化满足 constexpr 函数 的要求时,该构造函数为 constexpr 。 - 此重载仅当 std:: is_default_constructible_v < T_0 > 为 true 时参与重载决议。
variant
,并通过
*
std::
get_if
<
other.
index
(
)
>
(
std::
addressof
(
other
)
)
对所含值进行
直接初始化
。否则,初始化一个
valueless_by_exception
的 variant。
-
此构造函数被定义为已删除,除非对
Types...
中的所有
T_i, std:: is_copy_constructible_v < T_i > 均为 true 。 -
若对
Types...
中的所有
T_i, std:: is_trivially_copy_constructible_v < T_i > 均为 true ,则此构造函数是平凡的。
variant
,并通过
直接初始化
使用
std
::
move
(
*
std::
get_if
<
other.
index
(
)
>
(
std::
addressof
(
other
)
)
)
初始化所含值。否则,初始化一个
valueless_by_exception
状态的 variant。
-
仅当对
Types...
中的所有
T_i满足 std:: is_move_constructible_v < T_i > 为 true 时,此重载才参与重载决议。 -
当对
Types...
中的所有
T_i满足 std:: is_trivially_move_constructible_v < T_i > 为 true 时,该构造函数是平凡构造函数。
T_j
的
variant
,该类型将通过重载决议为表达式
F
(
std::
forward
<
T
>
(
t
)
)
选择,如同对
Types...
中的每个
T_i
都存在虚构函数重载
F(T_i)
,但不考虑窄化转换。
形式化定义:
-
-
仅当声明
T_i x
[
]
=
{
std::
forward
<
T
>
(
t
)
}
;
对某个虚构变量
x有效时,才会考虑重载 F ( T_i ) 。
-
仅当声明
T_i x
[
]
=
{
std::
forward
<
T
>
(
t
)
}
;
对某个虚构变量
-
此重载仅在以下情况参与重载决议:
- sizeof... ( Types ) > 0 ,
-
std::
decay_t
<
T
>
(C++20 前)
std::
remove_cvref_t
<
T
>
(C++20 起)
既不是
variant的相同类型,也不是 std::in_place_type_t 的特化,也不是 std::in_place_index_t 的特化, - std:: is_constructible_v < T_j, T > 为 true ,
- 且表达式 F ( std:: forward < T > ( t ) ) (其中F是上述虚构函数集合)是良构的。
-
若
T_j的选定构造函数是constexpr构造函数,则此构造函数为 constexpr 构造函数。
std::variant<std::string> v("abc"); // 正确 std::variant<std::string, std::string> w("abc"); // 非良构 std::variant<std::string, const char*> x("abc"); // 正确,选择 const char* std::variant<std::string, bool> y("abc"); // 正确,选择 string;bool 不是候选类型 std::variant<float, long, double> z = 0; // 正确,持有 long // float 和 double 不是候选类型
T
的
variant
,并使用参数
std::
forward
<
Args
>
(
args
)
...
初始化所含值。
-
如果
T的选定构造函数是 constexpr 构造函数,则此构造函数也是 constexpr 构造函数。 -
此重载仅在以下条件下参与重载决议:
Types...
中
T仅出现一次,且 std:: is_constructible_v < T, Args... > 为 true 。
T
的
variant
,并使用参数
il,
std::
forward
<
Args
>
(
args
)
...
初始化所容纳的值。
-
如果
T的选定构造函数是 constexpr 构造函数,则此构造函数也是 constexpr 构造函数。 -
仅当
Types...
中
T仅出现一次,且 std:: is_constructible_v < T, initializer_list < U > & , Args... > 为 true 时,此重载才会参与重载决议。
I
指定的备选类型
T_i
的
variant
,并使用参数
std::
forward
<
Args
>
(
args
)
...
初始化所含值。
-
若
T_i选择的构造函数是 constexpr 构造函数,则此构造函数同样是 constexpr 构造函数。 - 此重载仅当 I < sizeof... ( Types ) 且 std:: is_constructible_v < T_i, Args... > 为 true 时参与重载决议。
I
指定的可选类型
T_i
的
variant
,并使用参数
il,
std::
forward
<
Args
>
(
args
)
...
初始化所含值。
-
如果
T_i选择的构造函数是 constexpr 构造函数,则此构造函数也是 constexpr 构造函数。 - 此重载仅在满足 I < sizeof... ( Types ) 且 std:: is_constructible_v < T_i, std:: initializer_list < U > & , Args... > 为 true 时参与重载决议。
目录 |
参数
| other | - |
另一个待复制/移动其内含值的
variant
对象
|
| t | - | 用于初始化内含值的值 |
| args... | - | 用于初始化内含值的参数 |
| il | - | 用于初始化内含值的初始化列表 |
异常
T_i
时抛出的任何异常。
T_i
时抛出的异常。
T_j
初始化过程中抛出的任何异常。
注释
MSVC STL 最初将 P0608R3 视为 C++20 的变更。自 VS 2022 17.12 起,MSVC STL 也将 P0608R3 视为针对 C++17 的缺陷报告。
示例
#include <cassert> #include <iostream> #include <string> #include <variant> #include <vector> using vector_t = std::vector<int>; auto& operator<<(auto& out, const vector_t& v) { out << "{ "; for (int e : v) out << e << ' '; return out << '}'; } int main() { // 值初始化第一个备选项 std::variant<int, std::string> var0; assert(std::holds_alternative<int>(var0) and var0.index() == 0 and std::get<int>(var0) == 0); // 使用 std::string{"STR"} 初始化第一个备选项 std::variant<std::string, int> var1{"STR"}; assert(var1.index() == 0); std::cout << "1) " << std::get<std::string>(var1) << '\n'; // 使用 int == 42 初始化第二个备选项 std::variant<std::string, int> var2{42}; assert(std::holds_alternative<int>(var2)); std::cout << "2) " << std::get<int>(var2) << '\n'; // 使用 std::string{4, 'A'} 初始化第一个备选项 std::variant<std::string, vector_t, float> var3 { std::in_place_type<std::string>, 4, 'A' }; assert(var3.index() == 0); std::cout << "3) " << std::get<std::string>(var3) << '\n'; // 使用 std::vector{1,2,3,4,5} 初始化第二个备选项 std::variant<std::string, vector_t, char> var4 { std::in_place_type<vector_t>, {1, 2, 3, 4, 5} }; assert(var4.index() == 1); std::cout << "4) " << std::get<vector_t>(var4) << '\n'; // 使用 std::string{"ABCDE", 3} 初始化第一个备选项 std::variant<std::string, vector_t, bool> var5 {std::in_place_index<0>, "ABCDE", 3}; assert(var5.index() == 0); std::cout << "5) " << std::get<std::string>(var5) << '\n'; // 使用 std::vector(4, 42) 初始化第二个备选项 std::variant<std::string, vector_t, char> var6 {std::in_place_index<1>, 4, 42}; assert(std::holds_alternative<vector_t>(var6)
缺陷报告
以下行为变更缺陷报告被追溯应用于先前发布的C++标准。
| 缺陷报告 | 适用版本 | 发布时行为 | 修正后行为 |
|---|---|---|---|
| LWG 2901 | C++17 |
提供了分配器感知构造函数但
variant
无法正确支持分配器
|
移除构造函数 |
| P0739R0 | C++17 |
转换构造函数模板与类模板
参数推导配合不佳 |
添加约束条件 |
| LWG 3024 | C++17 |
若任何成员类型不可复制则
拷贝构造函数不参与重载决议 |
改为定义为删除 |
| P0602R4 | C++17 |
即使底层构造函数是平凡
拷贝/移动构造函数也可能非平凡 |
要求传播平凡性 |
| P0608R3 | C++17 |
转换构造函数盲目组合重载集
导致非预期的转换 |
不考虑窄化和布尔转换 |
| P1957R2 | C++17 |
bool
的转换构造函数不允许
隐式转换 |
指针到
bool
的转换属于窄化且
转换构造函数未对 bool 提供特殊处理 |