Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return Optional value with ?: operator

I often need to use optional type for functions:

std::optional<int32_t> get(const std::string& field) {     auto it = map.find(field);     if (it != map.end()) return it->second;     return {}; } 

Is there a way to return optional value in one line? e.g. this:

std::optional<int32_t> get(const std::string& field) {     auto it = map.find(field);     return it != map.end() ? it->second : {}; } 

results in the error

error: expected primary-expression before '{' token return it != map.end() ? it->second : {};                                       ^ 
like image 516
MiP Avatar asked Jul 29 '17 13:07

MiP


People also ask

Is std :: optional a pointer?

The class template std::optional manages an optional contained value, i.e. a value that may or may not be present[1]. It is a great alternative for std::unique_ptr , or raw pointer, when used solely to express that a value is indeed optional.

Does STD optional allocate?

Any instance of optional<T> at any given point in time either contains a value or does not contain a value. If an optional<T> contains a value, the value is guaranteed to be allocated as part of the optional object footprint, i.e. no dynamic memory allocation ever takes place.

What does STD optional do?

C++17 introduced std::optional<T> which lets you augment the values of a type T with a bonus value known as std::nullopt which semantically represents the absence of a value. A std::optional which holds the value std::nullopt is known as empty.

Does STD optional allocate memory?

What's more, std::optional doesn't need to allocate any memory on the free store. std::optional is a part of C++ vocabulary types along with std::any , std::variant and std::string_view .


2 Answers

You can explicitly wrap the some-value return into an std::optional, and fall back on the constexpr std::nullopt for the no-value return.

std::nullopt:

std::nullopt is a constant of type std::nullopt_t that is used to indicate optional type with uninitialized state.

...

std::nullopt_t:

std::nullopt_t is an empty class type used to indicate optional type with uninitialized state. In particular, std::optional has a constructor with nullopt_t as a single argument, which creates an optional that does not contain a value.

With this approach, the true clause of the ternary operator call explicitly returns an std::optional with a some-value, so the compiler can deduce the template parameter/wrapped type (in this example: int32_t) from the type of the supplied wrapped value, meaning you needn't specify it explicitly.

Applied to your example:

return it != map.end() ? std::optional(it->second) : std::nullopt;  // alternatively return it != map.end() ? std::make_optional(it->second) : std::nullopt; 
like image 59
dfrib Avatar answered Oct 03 '22 00:10

dfrib


return it != map.end() ? it->second : std::optional<int32_t>{}; 

should do the trick.

The compiler must deduce the result type of the ternary expression from the last two operands, but there is no way it can deduce std::optional<int32_t> from int32_t and {}.

int32_t and std::optional<int32_t> on the other hand do have the desired common type std::optional<int32_t>.


Related fun fact: You can avoid repeating the type with auto return type deduction:

auto get(const std::string& field) {     auto it = map.find(field);     return it != map.end() ? it->second : std::optional<int32_t>{}; } 

Depending on preference, you can of course also infer the template argument for the std::optional from it->second with decltype to further reduce repetition.

like image 34
Baum mit Augen Avatar answered Oct 02 '22 23:10

Baum mit Augen