为什么range :: ostream_iterator默认可构造?

ein*_*ica 6 c++ iterator ostream range-v3 c++20

这个问题在这里的评论中进行了讨论。

在Eric Niebler的ranges-v3库(某种程度上已成为C ++ 20标准的一部分)中,它ranges::ostream_iterator默认可构造的 -没有ostream。

怎么来的?

我认为后来具有有效构造的“虚拟”构造是C ++中的反模式,我们逐渐摆脱了这种疣。std::ostream iterator 只能使用流构造(目前-在C ++ 20之前)。而且,似乎我们无法使用默认构造的东西做任何事情range::ostream_iterator。。。所以,这是怎么回事?

Bar*_*rry 8

这遵循类型应该如何表现的“编程元素”设计哲学。如果您听到过“做做int”的话,那就是哲学-类型应该是Regular。而EoP 对Regular的定义是:

T的计算基础包括相等性,赋值,析构函数,默认构造函数,复制构造函数,总排序(或默认总排序)和基础类型

转换为真正的C ++ 20概念为:

template<class T>
  concept Movable = is_object_v<T> && MoveConstructible<T> && Assignable<T&, T>
    && Swappable<T>;
template<class T>
  concept Copyable = CopyConstructible<T> && Movable<T> && Assignable<T&, const T&>;
template<class T>
  concept Semiregular = Copyable<T> && DefaultConstructible<T>;
template<class T>
  concept Regular = Semiregular<T> && EqualityComparable<T>;
Run Code Online (Sandbox Code Playgroud)

我们已经失去了总订购部分,而只选择简单EqualityComparable,即使如此,通过Ranges进行的许多库需求实际上只需要Semiregular-不需要Regular。但这仍然是这个想法的基础。

请注意,如果类型是可移动的,则默认可构造类型已经很有意义。从概念上移出的状态与默认构造的状态非常相似。从那里不能做很多事情,但这是一个状态。

  • 始终要求前进和后退迭代器必须是默认可构造的,但不一定要有用的任何迭代器(请参见指针)。这种变化使事情变得更加统一。 (2认同)

Nic*_*las 8

在 C++ 中有很多事情,非默认构造的类型根本不可行。这是一个非常简单的示例:Tistreamusing>>运算符中提取类型而无需默认构造T(或以其他方式提供 live T)。你不能,因为接口本身要求一个存在。该接口旨在假设您始终可以构造可提取类型的对象。

如果没有给你一个对象来使用,那就意味着默认构造它。

这似乎是一个精心挑选的例子,但事实并非如此。在通用代码中,有时只需要创建 aT以便稍后填充它的位,这是一种半频繁的情况。

无论我们多么想说对象只有在它们处于这种状态有意义的情况下才应该是默认可构造的,但这根本不是实际的现实。有时,你只需要现在创建一个对象,然后用一个有用的值填充它。

因此,Ranges v3 库在基本且常用的概念 SemiRegular 中体现了这一要求。这个概念代表了对象操作的一些更基本的方面:我可以制作一个,我可以分配它。迭代器需要遵循这个概念。


还应该注意的是,在 C++20 中,ostream_iterator获得了一个默认构造函数