[英]How does std::optional construct std::variant in place from initializer list?
#include <optional>
#include <variant>
#include <utility>
#include <set>
int main()
{
std::optional<std::variant<std::pair<int, int>, std::set<int>>> foo(std::in_place, {1, 4});
}
std::variant
does not have a constructor that takes std::initializer_list<T>
as its first argument , but all that this constructor overload of std::optional
does is pass the initializer list and forward other arguments to the internal type constructor ?std::variant
没有将std::initializer_list<T>
作为其第一个参数的构造函数时,这怎么可能呢,但是std::optional
这个构造函数重载所做的只是传递初始化列表并转发其他参数到内部类型构造函数?std::variant
hold now, std::set
or std::pair
? std::variant
现在持有哪种类型, std::set
或std::pair
?It's a bit complicated, so bear with me.这有点复杂,所以请耐心等待。
optional<T>
has a constructor that takes an in_place_t
and an initializer_list<U>
(and optional extra arguments). optional<T>
有一个构造函数,它接受一个in_place_t
和一个initializer_list<U>
(以及可选的额外参数)。 It will then attempt to construct T
as if by this statement:然后它将尝试构造
T
就像通过以下语句一样:
T t(list, ...);
Where list
is the initailizer list and ...
are any extra arguments.其中
list
是初始化程序列表,而...
是任何额外的参数。
T
is of course a variant<pair, set>
. T
当然是一个variant<pair, set>
。 variant
is implicitly convertible from any type V
through a template constructor. variant
可以通过模板构造函数从任何类型V
隐式转换。 However, this constructor only exists if V
is a type such that, given a value v
of this type, the following is true:然而,只有当
V
是一个类型时,这个构造函数才存在,这样,给定一个这个类型的值v
,下面是真的:
W w(std::forward<V>(v));
Where W
(I'm running out of letters here) is one of the types in the variant
. W
(我在这里用完了字母)是variant
中的类型之一。 Now variant
can have multiple types, so variant
basically considers all possible W
s and their constructor overloads.现在
variant
可以有多种类型,所以variant
基本上考虑了所有可能的W
及其构造函数重载。 So long as overload resolution selects exactly one such constructor among all possible W
s in the variant
, the conversion will work.只要重载决议在所有可能的
W
variant
选择了一个这样的构造函数,转换就会起作用。
pair
has no constructor that takes an initializer_list
, so none of its constructors count. pair
没有带initializer_list
构造initializer_list
,所以它的构造函数都不算数。 set<X>
has a constructor that takes an initializer_list<X>
. set<X>
有一个构造函数,它接受一个initializer_list<X>
。
So, back to the original statement.所以,回到最初的陈述。 Because
optional
had an initializer_list<Y>
parameter where Y
is deduced, the braced-init-list will deduce Y
as int
.因为
optional
有一个initializer_list<Y>
参数,其中Y
是推导的,所以花括号初始化器列表会将Y
推导为int
。 And int
is the same type as the set
in the variant
.并且
int
与variant
的set
类型相同。 So set<int>
can be constructed from an initailizer_list<int>
.所以
set<int>
可以从initailizer_list<int>
构造。
And therefore, that's what gets created in the variant
.因此,这就是在
variant
创建的内容。
If you had a vector<int>
as part of the variant
, you'd get a compile error due to the ambiguity of which to call.如果你有一个
vector<int>
作为variant
一部分,你会因为调用的不明确而得到一个编译错误。
And there's not really a way to fix that through in_place
gymnastics.并没有真正的方法可以通过
in_place
体操来解决这个in_place
。 You can't do (std::in_place, std::in_place_type<std::set>, {1, 4})
, because the braced-init-list won't get properly deduced.您不能这样做
(std::in_place, std::in_place_type<std::set>, {1, 4})
,因为无法正确推断出花括号初始化器列表。 So you'd have to do (std::in_place, std::set{1, 4})
and let move construction move from the temporary into the variant
.所以你必须做
(std::in_place, std::set{1, 4})
并让移动构造从临时移动到variant
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.