Зачем нам нужен std::nullopt

Когда мы можем использовать юниформ-инициализацию, чтобы легко создать по умолчанию std::optional<T>?

std::optional<T> foo() {
   if (on_error)
      return {};

    // ...
}

Есть ли недостаток в вышеизложенном, который решает std::nullopt?


person Sebastian Hoffmann    schedule 16.07.2020    source источник
comment
или [Разница между nullptr, {} и nullopt](stackoverflow.com/questions/47791737/   -  person underscore_d    schedule 16.07.2020


Ответы (2)


Нет

Это вполне допустимый способ построения по умолчанию optional.

Даже для назначения вы можете скопировать-назначить построенный по умолчанию optional с = {} вместо использования std::nullopt:

cppreference на самом деле говорит об этом:

Существуют ограничения на конструкторы nullopt_t для поддержки как op = {};, так и op = nullopt; в качестве синтаксиса для отключения необязательного объекта.

… как и исходное предложение по функция:

Обратите внимание, что это не единственный способ отключить необязательный объект. Вы также можете использовать:

op = std::nullopt;

Вы можете спросить себя, почему тогда std::nullopt вообще существует. В предложении это тоже рассматривается< /а>:

это вводит избыточность в интерфейс

[похожий пример]

С другой стороны, есть случаи, когда использование nullopt нельзя заменить никаким другим удобным обозначением:

void run(complex<double> v);
void run(optional<string> v);

run(nullopt);              // pick the second overload
run({});                   // ambiguous

if (opt1 == nullopt) ...   // fine
if (opt2 == {}) ...        // illegal

bool is_engaged( optional<int> o)
{
  return bool(o);          // ok, but unclear
  return o != nullopt;     // familiar
}

Хотя в некоторых ситуациях синтаксис {} будет работать, использование nullopt делает намерение программиста более ясным. Сравните это:

optional<vector<int>> get1() {
  return {};
}

optional<vector<int>> get2() {
  return nullopt;
}

optional<vector<int>> get3() {
  return optional<vector<int>>{};
}

Короче говоря, std::nullopt может быть полезен, но в вашем случае это просто сводится к стилю.

person Asteroids With Wings    schedule 16.07.2020

Есть ли какой-либо недостаток в вышеизложенном, который решает std::nullopt?

Да.

В некоторых контекстах вы можете захотеть условно вернуть отключенный необязательный объект (пустой, если хотите), а синтаксис инициализации {} нельзя однозначно использовать для вывода типа std::nullopt_t. Например, как описано в разделе Возврат необязательного значения с помощью оператора ?:, при возврате пустого или непустого параметра через выражение тернарного оператора:

return it != map.end() ? std::make_optional(it->second) : std::nullopt;
person dfrib    schedule 16.07.2020
comment
правильно ли я понимаю, что это применимо только в том случае, если возвращаемый тип функции объявлен как auto? - person Sebastian Hoffmann; 16.07.2020
comment
@SebastianHoffmann Нет, вам даже не нужна функция: wandbox.org/permlink/ICRS7wfj801CgGIf - person Thomas Sablik; 16.07.2020
comment
Связанный вопрос касается другого случая. Ваше выражение true соответствует типу возвращаемого значения. Но, тем не менее, выражение {} здесь недопустимо. - person Asteroids With Wings; 16.07.2020
comment
Это прояснило ситуацию, спасибо - person Sebastian Hoffmann; 16.07.2020