Рекомендуется использоватьнеобязательно<T>
в ситуациях, когда есть ровно одна, четкая (для всех сторон) причина отсутствия значения типа.T
, и где недостаток стоимости столь же естественно, как и наличие какой-либо регулярной стоимости.T
. Одним из примеров такой ситуации является просьба к пользователю в какой-либо форме графического интерфейса необязательно указать некоторое ограничение на значениеint
, но пользователю разрешается сказать: «Я хочу, чтобы число не было ограничено максимумом». В другом примере рассмотрим параметр конфигурации, определяющий, сколько потоков должно быть запущено приложением. Оставить этот параметр неуказанным означает, что приложение должно решить само. Для еще одного примера рассмотрим функцию, возвращающую индекс наименьшего элемента в векторе
. Мы должны быть готовы к ситуации, когда вектор
пуст. Таким образом, естественным признаком такой функции было бы:
template <typename T>
optional<size_t> find_smallest_elem(const std::vector<T>& vec);
Здесь, получив пустойvec
и не имеяразмер_t
, чтобы вернуться неотказ, нонормальная, хотя и нерегулярная, ситуация.
Другая типичная ситуация заключается в том, что у нас еще нет ценности, но мы ожидаем, что она появится позже. Это понятие может быть использовано при реализации таких решений, как ленивая инициализация или двухфазная инициализация.
факультативный
может быть использован для взятия неDefaultConstructible
типаT
и создания родственного типа с конструктором по умолчанию. Это способ добавить нулевое состояниек любому типу, у которого его еще нет.
Иногда типT
уже обеспечивает встроенное нулевое состояние, но все же может быть полезно обернуть его внеобязательно
. Рассмотримstd::строку
. Когда вы читаете фрагмент текста из GUI-формы или таблицы DB, едва ли пустая строка указывает на что-либо еще, кроме отсутствующего текста. И некоторые базы данных даже не различают нулевую строку ввода и ненулевую строку длины 0. Тем не менее, может быть практичным использоватьнеобязательно<строку>
, чтобы указать в возвращенном типе, что мы хотим обработать пустую строку в специальном выделенном программном пути:
if(boost::optional<std::string> name = ask_user_name()) {
assert(*name != "");
logon_as(*name);
}
else {
skip_logon();
}
В приведенном выше примере утверждение указывает на то, что, если мы решим использовать этот метод, мы должны перевести состояние пустой строки на необязательный объект без содержащегося значения (внутренняя функцияask_user_name
).
Не рекомендуется использоватьнеобязательно
, чтобы указать, что мы не смогли вычислить значение из-заотказа. Трудно определить, что такое сбой, но обычно он имеет одну общую характеристику: связанную информацию о причине сбоя. Это могут быть данные типа и члена объекта исключения или код ошибки. Это плохой дизайн, чтобы сигнализировать о сбое и не сообщать о причине. Если вы не хотите использовать исключения, и вам не нравится тот факт, что, возвращая коды ошибок, вы не можете вернуть вычисленное значение, вы можете использовать библиотекуОжидаемое. Это своего родаBoost.Variant, который содержит либо вычисленное значение, либо причину, по которой вычисления не удались.
Иногда различие между неудачей и действительным, но нерегулярным результатом размыто и зависит от конкретного использования и личных предпочтений. Рассмотрим функцию, которая преобразует строку
вint
. Это провал, который вы не можете конвертировать? В некоторых случаях это может быть так, но в других вы можете назвать это именно для того, чтобы выяснить, является ли даннаястрока.
является конвертируемым, и вас даже не интересует полученное значение. Иногда, когда конверсия терпит неудачу, вы можете не считать ее неудачей, но вам нужно знать, почему она не может быть преобразована; например, при каком характере определяется, что конверсия невозможна. В этом случае возвратфакультативного<T>
будет недостаточным. Наконец, существует случай использования, когда входная строка не представляетint.
не является условием отказа, но во время конверсии мы используем ресурсы, приобретение которых может потерпеть неудачу. В этом случае естественное представление состоит как в возвратенеобязательного<int>
, так и в отказе сигнала:
optional<int> convert1(const string& str);
expected<ErrorT, optional<int>> convert2(const string& str);