如何解决为什么 range::single_view 对底层值使用花括号初始化?
根据[range.single.view#3],std::ranges::single_view
构造函数之一定义为:
template<class... Args>
requires constructible_from<T,Args...>
constexpr explicit single_view(in_place_t,Args&&... args);
Effects:初始化 value_
就像用 value_{in_place,std::forward<Args>(args)...}
一样。
为什么标准指定使用direct-list-initialization ({}
) 来初始化value_
?为什么不像 direct-initialization、()
和 std::variant
一样使用 std::optional
(std::any
)?
此外,std::constructible_from
(std::is_constructible
) 指定 T obj(std::declval<Args>()...)
是格式良好的,而不是 T obj{std::declval<Args>()...}
。
考虑following:
ranges::single_view<std::vector<int>> sv(std::in_place,100,0);
std::cout << sv.begin()->size() << "\n"; // #1
std::optional<std::vector<int>> op(std::in_place,0);
std::cout << op->size() << "\n"; // #2
因为使用了不同的初始化,#1
会调用std::vector<int>{0,100}
并打印2
,而#2
会调用std::vector<int>(0,100)
并打印{{1} }.
为什么标准指定使用花括号初始化底层值,即使它可能会导致不一致?这背后的考虑是什么?
解决方法
value_
是一个 semiregular-box
,因此它的构造函数是众所周知的,并且不包含初始化列表构造函数。不会出现不一致,因为在这种情况下大括号和括号是等效的 - 底层类型将始终用括号构造,因为这是 semiregular-box
的构造函数指定要做的事情。
您观察到的行为是一个 libstdc++ 错误。
至于为什么 range 子句普遍使用列表初始化 - 没有充分的理由,它实际上导致了问题。 LWG 已批准了一篇论文 (P2367),该论文将消除对具有规范影响的列表初始化的滥用;剩余部分由 editorial issue 4593 跟踪。
,#1 将调用 std::vector{0,100}
不,不会。
value_
属于 semiregular-box<T>
类型,它是一种仅用于说明的类型,其作用类似于 optional<T>
,但是 with some differences。但这些差异在此处不适用,因此您可以将其视为只是 optional<T>
。
一个 initializer_list
只有在表达式的所有类型都相同的情况下才能从花括号初始化列表形成(或者如果它们可以转换为某种类型而不会缩小)。但是 {in_place,std::forward<Args>(args)...}
以类型 std::in_place_t
开头,这几乎肯定不是 Args
的类型之一。所以不能从中形成 initializer_list
。
即使用户确实提供了 in_place_t
作为 Args
(也许他们正在做 single_view<optional<T>>
或其他事情),也没关系,因为 optional
(和因此 semiregular-box
) 没有 initializer_list
构造函数。因此它会调用匹配的常规构造函数,就像您使用 ()
一样。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。