Почему range :: ostream_iterator конструируется по умолчанию? - PullRequest
5 голосов
/ 11 мая 2019

Этот вопрос следует за обсуждением в комментариях здесь .

В библиотеке Эрика Ниблера range-v3 (что-то вродестав частью стандарта для C ++ 20), ranges::ostream_iterator является конструируемым по умолчанию - без ostream.

Почему?

Я думал, что «фиктивная» конструкция с эффективной конструкцией позже является анти-паттерном в C ++, бородавкой, от которой мы постепенно избавляемся.std::ostream iterator может быть создан только с потоком (сейчас - до C ++ 20).И это не так, как будто мы можем сделать что-нибудь с построенным по умолчанию range::ostream_iterator ... Итак, в чем же дело?

Ответы [ 2 ]

7 голосов
/ 11 мая 2019

Это следует из философии проектирования Элементов программирования о том, как должны вести себя типы. Если вы слышали фразу «делай как int s», то есть философия - типы должны быть Regular. И определение Regular EoP равно:

Основа вычисления 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>;

Мы потеряли часть общего порядка в пользу просто EqualityComparable, и даже тогда для многих библиотечных требований через диапазоны требуется только Semiregular - не Regular. Но тем не менее, это основа идеи.

Обратите внимание, что если тип является подвижным, то уже имеет смысл, чтобы он был конструируемым по умолчанию. Состояние отъезда очень концептуально похоже на состояние, созданное по умолчанию. Оттуда мало что можно сделать, но это состояние.

3 голосов
/ 11 мая 2019

В C ++ есть много вещей, где не конструируемый по умолчанию тип просто не работает. Вот очень простой пример: извлеките тип T из istream, используя оператор >> без конструкции по умолчанию T (или иным образом получая живой T). Вы не можете, потому что сам интерфейс требует, чтобы он существовал. Интерфейс рассчитан на то, что вы всегда можете создать объект извлекаемого типа.

А если вам не дан объект для работы, это означает, что по умолчанию он создается.

Это похоже на вишневый пример, но это не так. Это частое явление, когда в общем коде вам иногда нужно просто создать T, чтобы вы могли заполнить его позже.

Сколько бы мы ни хотели сказать, что объекты должны быть конструируемыми по умолчанию, только если для них имеет смысл находиться в таком состоянии, это просто не является практической реальностью. Иногда вам просто нужно создать объект сейчас, а потом заполнить его полезным значением.

Таким образом, библиотека Ranges v3 закрепляет это требование в базовой и часто используемой концепции SemiRegular. Эта концепция представляет некоторые из основных аспектов манипулирования объектами: я могу создать один и назначить его. Итераторы должны следовать этой концепции.


Следует также отметить, что в C ++ 20 ostream_iterator получает конструктор по умолчанию .

...