I can't get an optional with (cond) ? value : nullopt ... what should I write instead?

I can't get an optional with (cond) ? value : nullopt ... what should I write instead?

Suppose I'm implementing the function returning an std::optional<T>. In that function, I compute some condition, and then want to return either a value, or a nullopt. I can do it like so:

std::optional<T> foo()
{
  auto cond = compute_condition();
  if (cond) return compute_value();
  return std::nullopt;
}

and this works fine. But - I want a one-liner. I would have liked to be able to write:

std::optional<T> foo()
{
  return (compute_condition()) ? compute_value() : std::nullopt;
}

but this fails to compile (GodBolt.org):

error: operands to '?:' have different types 'T' and 'const std::nullopt_t'

is there something in the standard I can use?

Note: This question is related, but less general.

Answer

I don't think there's anything in the standard catering to your use-case. Here is a flawed, less efficient, but mostly decent-looking, and non-idiomatic, solution:

Use following utility function template:

template <typename T>
std::optional<T> value_if(bool cond, T&& value)
{
  if (cond) return value;
  return std::nullopt;
}

and then write:

std::optional<T> foo()
{
  return value_if<int>(compute_condition(), compute_value());
}

... but - this has the drawback of always computing the value, even if the condition does not hold.


Q: Why are you specifying T in the invocation of value_if()?

A: That's because the result of compute_value() may need to undergo implicit conversion to fit the optional's type. If I just let T be deduced, I might get the wrong optional.

Enjoyed this question?

Check out more content on our blog or follow us on social media.

Browse more questions