Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do we need std::nullopt [duplicate]

Tags:

c++

c++17

When we can use uniform initialization to easily default construct a std::optional<T>?

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

    // ...
}

Is there any drawback to the above which std::nullopt solves?

like image 384
Sebastian Hoffmann Avatar asked Jul 16 '20 11:07

Sebastian Hoffmann


Video Answer


2 Answers

No.

This is a perfectly valid way to default-construct an optional.

Even for assignment, you can copy-assign a default-constructed optional with = {} instead of using std::nullopt:

cppreference actually says as much:

The constraints on nullopt_t's constructors exist to support both op = {}; and op = nullopt; as the syntax for disengaging an optional object.

… as does the original proposal for the feature:

Note that it is not the only way to disengage an optional object. You can also use:

op = std::nullopt;

You might ask yourself why, then, std::nullopt exists at all. The proposal addresses this, too:

it introduces redundancy into the interface

[similar example]

On the other hand, there are usages where the usage of nullopt cannot be replaced with any other convenient notation:

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
}

While some situations would work with {} syntax, using nullopt makes the programmer's intention more clear. Compare these:

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

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

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

In short, std::nullopt can be useful, but in your case it simply comes down to style.

like image 132
Asteroids With Wings Avatar answered Sep 29 '22 19:09

Asteroids With Wings


Is there any drawback to the above which std::nullopt solves?

Yes.

In some contexts you may want to conditionally return a disengaged optional object (empty, if you’d like) and the {} initialization syntax cannot be non-ambiguously used to deduce the std::nullopt_t type. E.g., as is covered in Return Optional value with ?: operator, when returning an empty or non-empty optional through a ternary operator expression:

return it != map.end() ? std::make_optional(it->second) : std::nullopt;
like image 42
dfrib Avatar answered Sep 29 '22 19:09

dfrib