How should one use std::optional?

The simplest example I can think of:

std::optional<int> try_parse_int(std::string s)
{
    //try to parse an int from the given string,
    //and return "nothing" if you fail
}

The same thing might be accomplished with a reference argument instead (as in the following signature), but using std::optional makes the signature and usage nicer.

bool try_parse_int(std::string s, int& i);

Another way that this could be done is especially bad:

int* try_parse_int(std::string s); //return nullptr if fail

This requires dynamic memory allocation, worrying about ownership, etc. - always prefer one of the other two signatures above.


Another example:

class Contact
{
    std::optional<std::string> home_phone;
    std::optional<std::string> work_phone;
    std::optional<std::string> mobile_phone;
};

This is extremely preferable to instead having something like a std::unique_ptr<std::string> for each phone number! std::optional gives you data locality, which is great for performance.


Another example:

template<typename Key, typename Value>
class Lookup
{
    std::optional<Value> get(Key key);
};

If the lookup doesn't have a certain key in it, then we can simply return "no value."

I can use it like this:

Lookup<std::string, std::string> location_lookup;
std::string location = location_lookup.get("waldo").value_or("unknown");

Another example:

std::vector<std::pair<std::string, double>> search(
    std::string query,
    std::optional<int> max_count,
    std::optional<double> min_match_score);

This makes a lot more sense than, say, having four function overloads that take every possible combination of max_count (or not) and min_match_score (or not)!

It also eliminates the accursed "Pass -1 for max_count if you don't want a limit" or "Pass std::numeric_limits<double>::min() for min_match_score if you don't want a minimum score"!


Another example:

std::optional<int> find_in_string(std::string s, std::string query);

If the query string isn't in s, I want "no int" -- not whatever special value someone decided to use for this purpose (-1?).


For additional examples, you could look at the boost::optional documentation. boost::optional and std::optional will basically be identical in terms of behavior and usage.


An example is quoted from New adopted paper: N3672, std::optional:

 optional<int> str2int(string);    // converts int to string if possible

int get_int_from_user()
{
     string s;

     for (;;) {
         cin >> s;
         optional<int> o = str2int(s); // 'o' may or may not contain an int
         if (o) {                      // does optional contain a value?
            return *o;                  // use the value
         }
     }
}