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

2022-01-10 00:00:00 iterator c++ c++20 range-v3 ostream

这个问题是在这里的评论中讨论的.

在 Eric Niebler 的 ranges-v3 库中(有点像是成为C++20 的标准),ranges::ostream_iterator 是 default-constructible - 没有 ostream.

怎么会?

我认为后来有效构造的虚拟"构造是 C++ 中的一种反模式,我们正在逐渐摆脱它.std::ostream iterator 只能用流构造(现在 - 在 C++20 之前).而且好像我们不能用默认构造的 range::ostream_iterator 做任何事情......那么,有什么关系呢?

解决方案

作为对此的更新,P2325R3 刚刚被采用,这使得 std::ostream_iterator 不再是默认可构造的(在 C++20 中曾短暂地如此).


这遵循了编程元素的设计理念,即类型应该如何表现.如果你听说过do as the ints do"这句话,那就是哲学――类型应该是Regular.而EoPRegular的定义是:

<块引用>

T的计算基础包括相等、赋值、析构函数、默认构造函数、复制构造函数、全序(或默认全序)和底层类型

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

<块引用>

模板概念可动=is_object_v;&&MoveConstructible<T>&&可分配的<T&,T>&&可交换<T>;模板<类T>概念Copyable = CopyConstructible<T>&&可移动的<T>&&可赋值<T&, const T&>;模板<类T>概念半正则=可复制<T>&&DefaultConstructible<T>;模板<类T>概念正则 = 半正则<T>&&EqualityComparable<T>;

我们已经失去了总排序部分,转而支持简单的EqualityComparable,即便如此,许多通过 Ranges 的库需求实际上只需要 Semiregular - 不是 常规.但是,这仍然是这个想法的基础.

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

This question follows a discussion in the comments here.

In Eric Niebler's ranges-v3 library (which is sort-of becoming part of the standard for C++20), ranges::ostream_iterator is default-constructible - without an ostream.

How come?

I thought that "dummy" construction with effective construction later is an anti-pattern in C++, a wart we are gradually getting rid of. std::ostream iterator can only be constructed with a stream (for now - before C++20). And it's not as though we can do anything with the default-constructed range::ostream_iterator... So, what's the deal?

解决方案

As an update to this, P2325R3 was just adopted which makes std::ostream_iterator no longer default constructible (it was briefly made so in C++20).


This follows the Elements of Programming design philosophy of how types should behave. If you've heard the phrase "do as the ints do", that is that philosophy -- types should be Regular. And the EoP definition of Regular is:

T’s computational basis includes equality, assignment, destructor, default constructor, copy constructor, total ordering (or default total ordering) and underlying type

which translates to real C++20 concepts as:

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>;

We've lost the total ordering part in favor of simply EqualityComparable, and even then a lot of the library requirements via Ranges actually only require Semiregular - not Regular. But still, this is the foundation of the idea.

Note that if a type is movable, it already kind of makes sense for it to be default constructible. The moved-from state is very conceptually similar to a default-constructed state. Can't do much from there, but it's a state.

相关文章