3

根据[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);

效果value_­:如同按初始化value_­{in_­place, std​::​forward<Args>(args)...}­

为什么标准指定使用直接列表初始化{})来初始化value_?为什么不使用直接初始化( ()) 就像std::optional,std::variant和一样std::any

此外,std::constructible_from( std::is_constructible) 指定T obj(std::declval<Args>()...)是合式的,而不是T obj{std::declval<Args>()...}

考虑以下内容

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, 100, 0);
std::cout << op->size()         << "\n";  // #2

因为使用了不同的初始化,所以#1会调用std::vector<int>{0, 100}和打印2#2会调用std::vector<int>(0, 100)和打印100

为什么标准指定对基础值使用大括号初始化,即使它可能会导致不一致?这背后的考虑是什么?

4

2 回答 2

3

value_是 a semiregular-box,所以它的构造函数是众所周知的并且不包括初始化列表构造函数。不会出现不一致,因为在这种情况下大括号和括号是等价的 - 底层类型将始终使用括号构造,因为这是semiregular-box' 构造函数指定要做的事情。

您正在观察的行为是 libstdc++ 错误。


至于为什么范围子句普遍使用列表初始化 - 没有充分的理由,它实际上引起了问题。LWG 批准了一篇论文 (P2367),该论文将消除对具有规范影响的列表初始化的滥用;其余的由编辑问题 4593跟踪。

于 2021-05-07T14:45:32.447 回答
1

#1 将调用 std::vector{0, 100}

不,不会的。

value_是 类型semiregular-box<T>,这是一种仅用于说明的类型,其行为类似于optional<T>,但有一些区别。但是这些差异在这里并不适用,因此您可以将其视为只是optional<T>.

如果initializer_list表达式的所有类型都相同(或者如果它们可以转换为某种类型而无需缩小),则只能从花括号初始化列表形成。但从{in_­place, std​::​forward<Args>(args)...}­类型开始std::in_place_t,几乎可以肯定它不是 的类型之一Args。所以不能initializer_list从它形成。

即使用户确实提供了in_place_tas Args(也许他们正在single_view<optional<T>>做某事),也没关系,因为optional(因此semiregular-box)没有initializer_list构造函数。所以它会调用一个匹配的常规构造函数,就像你使用().

于 2021-05-07T14:53:27.110 回答