Тип дизайна: типы значений, конструируемость по умолчанию, необязательно & lt; T & gt; а его отношения?

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

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

Позже, есть некоторые типы, для которых построение их по умолчанию не дает значения. Например, в стандартной библиотеке у нас есть std::function<Sig> а также std::thread, например. Тем не менее, они являются конструируемыми по умолчанию, даже если они не содержат значения.

Позже мы предложили optional<T> в стандарте. Имеет смысл использовать его для базовых типов, поскольку для базовых типов все возможные назначения представляют допустимое значение (кроме double и float NaN), но я не понимаю, как бы вы использовали его для thread или std::function<Sig>, так как эти типы не содержат «значение» при создании. Это КАК ЕСЛИ эти типы были «необязательными», встроенными непосредственно в тип.

Это имеет эти недостатки. Поскольку не существует «естественной» конструкции по умолчанию (или значения), например, с помощью int:

  • Теперь я должен засорять свой класс if (valid) во всем моем дизайне и сигнализируют об ошибке. ИЛИ ЖЕ
  • сделать его менее безопасным, если я не сделаю эту проверку. Предварительное условие -> назначить перед использованием, если построено по умолчанию.

Поэтому, когда я хочу разработать тип, я всегда нахожу вопрос: должен ли я сделать его конструируемым по умолчанию?

Плюсы:

  • Проще использовать повторно в более общих контекстах, потому что мой тип будет легче моделировать SemiRegular или Regular, если я добавлю соответствующие операции.

Минусы:

  • Засорять весь класс if Заявления или заключение договора с пользователем, в котором класс является более небезопасным для использования.

Например, допустим, у меня есть класс Song с ID, исполнителем, названием, продолжительностью и годом. Для стандартной библиотеки очень приятно сделать тип по умолчанию конструктивным. Но:

  • Я не могу просто найти естественный способ создать «песню по умолчанию».
  • Я должен мусорить с if (validsong) или сделать его небезопасным.

Итак, мои вопросы:

  1. Как мне разработать тип, который не имеет «естественных (как в значении)» значений по умолчанию? Должен ли я предоставить конструктор по умолчанию или нет?

  2. В случае, если я хочу предоставить конструктор по умолчанию, как optional<T> вписаться во все эти головоломки? Я считаю, что создание типа, который не является «естественно» конструируемым по умолчанию, обеспечивает конструктор по умолчанию. optional<T> бесполезно в этом случае.

  3. Должен optional<T> просто использовать для типов, чья область значений полна, то есть я не могу присвоить недопустимое значение его представлению, потому что все они содержат значение, например, в int?

  4. Почему были такие типы, как std::function<Sig> сделал по умолчанию конструируемым на первом месте в стандарте? При создании он не содержит значения, поэтому я не понимаю, почему должен быть предоставлен конструктор по умолчанию. Вы всегда можете сделать: optional<function<void ()>>, например. Является ли это просто выбором дизайна, и оба действительны, или в этом случае существует один дизайн, в котором выбирается конструктив по умолчанию, а не конструктив по умолчанию, превосходящий другой?

3

Решение

(Примечание: проблема, связанная с большим количеством вопросов в одном вопросе, заключается в том, что некоторые его части могут дублироваться. Лучше задавать меньшие вопросы и проверять каждый на наличие предыдущих сообщений. «Один вопрос на вопрос» — это хорошая политика; легче сказать, чем сделать). иногда, я думаю.)

  1. Почему такие типы, как std :: function, сделали стандартно конструируемым по умолчанию в первую очередь в стандарте? При создании он не содержит значения, поэтому я не понимаю, почему должен быть предоставлен конструктор по умолчанию. Вы всегда можете сделать: optional<function<void ()>>, например.

Увидеть Почему экземпляры std :: function имеют конструктор по умолчанию?

  1. Как мне разработать тип, который не имеет «естественных (как в значении)» значений по умолчанию? Должен ли я предоставить конструктор по умолчанию или нет?

Конструкторы по умолчанию для типов, которым тяжело осмысленно определять себя без каких-либо данных, — это то, как многие классы реализуют нулевое значение. Необязательно ли лучший выбор? Я обычно так думаю, но я предполагаю, что вы знаете, что std::optional было проголосовал из C ++ 14. Даже если бы это был идеальный ответ, это не может быть ответом каждого … это еще не суп.

Это всегда добавляет некоторые накладные расходы для отслеживания времени выполнения, если значение привязано или нет. Возможно, не много накладных расходов. Но когда вы используете язык, смысл которого состоит в том, чтобы разрешить абстракцию, в то же время позволяя вам выстрелить себе в ногу настолько близко к металлу, насколько вы хотите … сбивание байта на значение в гигантском векторе может быть важным.

Так что даже если optional<T> Семантика и проверка во время компиляции были безупречны, вы все равно можете столкнуться со сценарием, в котором полезно удалить его и позволить вашему типу кодировать свою собственную недействительность. Должен подтолкнуть эти пиксели или полигоны или пакеты или … pfafftowns.

  1. В случае, если я решу предоставить конструктор по умолчанию, как необязательно вписывается в эту головоломку? Я считаю, что создание типа, который не является «естественно» конструируемым по умолчанию, предоставляет конструктор по умолчанию, что делает необязательный бесполезным в этом случае.

  2. Должен ли опционально использоваться только тип, чья область значений полна, то есть я не могу присвоить недопустимое значение его представлению, потому что все они содержат значение (за исключением float и double NaN, я думаю).

В моем собственном случае я обнаружил, что хочу во время компиляции различать процедуры, которые могут обрабатывать нулевые указатели, и те, которые не могут. Но вдруг optional<pointer> предложил такую ​​ситуацию: необязательный быть несвязанным, связанным с нулевым указателем и связанным с ненулевым указателем. Проверка работоспособности во время компиляции, похоже, меньше, чем победа.

Так как насчет необязательных ссылок? Они противоречивы в том смысле, что в последний раз я слышал, что они являются одной из точек преткновения в наборе вещей, которые задерживают std :: необязательный для C ++ 14. Что немного раздражало после того, как я преобразовал свои дополнительные указатели в дополнительные ссылки. : — /

У меня была смутная идея написать книгу о «патологическом C ++», где вы выбираете какую-то идею и начинаете приводить ее к логическим выводам. optional<T> был один удар, который я получил и придерживался принципов, которые вы определили. Удалите возможность кодирования «nullity» в самом типе, и затем неожиданно вы можете заставить компилятор выполнить проверку типов на предмет того, готов ли данный бит кода ожидать нулевое значение или нет.

(В эти дни я склонен подозревать, что если вы сильно зацикливаетесь на такого рода «патологическом C ++», то, возможно, вам придется заново изобретать Haskell.: — / См. Популярный Data.Maybe монада.)

1

Другие решения


По вопросам рекламы [email protected]