2

In the project I am currently working on I find myself writing a lot of code that looks like the following, where, get_optional_foo is returning an std::optional:

//...
auto maybe_foo = get_optional_foo(quux, ...)
if (!maybe_foo.has_value())
    return {};
auto foo = maybe_foo.value()
//...
// continue on, doing things with foo...

I want to bail out of the function if I get a null option; otherwise, I want to assign a non-optional variable to the value. I've started using the convention of naming the optional with a maybe_ prefix but am wondering if there is some way of doing this such that I don't need to use a temporary for the optional at all? This variable is only ever going to be used to check for a null option and dereference if there is a value.

jwezorek
  • 8,592
  • 1
  • 29
  • 46

3 Answers3

3

You don't need an intermediate object. std::optional supports a pointer interface to access it so you can just use it like:

//...
auto foo = get_optional_foo(quux, ...)
if (!foo)
    return {};
//...
foo->some_member;
(*foo).some_member;
cigien
  • 57,834
  • 11
  • 73
  • 112
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
1

Shortest I can think of:

auto maybe_foo = get_optional_foo(quux, ...)
if (!maybe_foo) return {};

auto &foo = *maybe_foo; // alternatively, use `*maybe_foo` below

If you have multiple optionals in the function and it's very unlikely they'll be empty you can wrap the whole thing with a try - catch.

try {
  auto &foo = get_optional_foo(quux, ...).value();
  auto &bar = get_optional_bar(...).value();
  ...
} catch (std::bad_optional_access &e) {
  return {};
}
Kostas
  • 4,061
  • 1
  • 14
  • 32
  • If you want shorter, you can write `return maybe_foo ? *maybe_foo : {}`. – ypnos Nov 11 '20 at 14:45
  • If we wanted to return, then we could just use `return maybe_foo.value_or({});` though. – Kostas Nov 11 '20 at 14:46
  • @ypnos Clang complains about this: `error: initializer list cannot be used on the right hand side of operator ':'`. – HolyBlackCat Nov 11 '20 at 14:53
  • @Kostas That would make an unnecessary default constructor call if the condition is false. – HolyBlackCat Nov 11 '20 at 14:54
  • @HolyBlackCat For `value_or({})`? I'm sure any decent compiler is happy to optimize this with copy elision. – Kostas Nov 11 '20 at 14:56
  • 1
    What I'm saying is, if the optional already stores a value, `{}` will still default-construct a new object, even if it's not needed. If the default constructor body is not visible, the compiler has to assume it could have side effects, and has to call it. – HolyBlackCat Nov 11 '20 at 15:05
1

Slightly different than what you are asking, but consider:

  if (auto foo = get_optional_foo(1)) {
    // ...
    return foo->x;
  } else {
    return {};
  }

This places the main body of the function in an if() block, which may be more readable.

Matt
  • 20,108
  • 1
  • 57
  • 70