Search code examples
c++c++17stdoptional

Get result into the caller from a function returning std::optional of std::vector


I am trying to manipulate the std::optional using container like std::vector.

I started by doing the code below :

#include <iostream>
#include <vector>
#include <string>
#include <optional>

using namespace std;

using optional_vecs = std::optional<std::vector<std::string>>;

optional_vecs returnStrings()
{
    optional_vecs myVect(std::in_place); 
    myVect->emplace_back("Name");
    return myVect;
}

int main()
{
    for (auto e : returnStrings().value())
        std::cout << e << " ";

    return 0;
}

The problem here is that I get nothing in the output: I guess that because std::optional::value return a reference as in my case it is a reference to a temporary.

So to resolve that I tried to use std::reference_wrapper as below :

using optional_vecs = std::optional<std::reference_wrapper<std::vector<std::string>>>;

optional_vecs returnStrings()
{
    optional_vecs myVect; 
    myVect->get().emplace_back("Name");
    return myVect;
}

Now I got a crash and an error :

  • the crash happens when trying to add the string "name".
  • the error is when I try to use the for-range loop saying the range for loop requires a suitable "begin" function and none was found.

The code below works but I don't like to declare a variable and then calli the Value():

int main()
{
    auto result = returnStrings();
    for (auto e : result.value())
        std::cout << e << " ";

    return 0;
}

So how could I return an std::optional holding a std::vector in the way functionName().Value().


Solution

  • Your issue here in the first two cases is that since returnStrings() returns a temporary, the for loop will not extend its life unless you actually capture what it returns. Capturing result.value() doesn't do you any good since it will not extend the lifetime of returnStrings().

    So how could I return an std::optional holding a std::vector in the way functionName().Value().

    You have to capture the return of functionName(). You can do what you did, or in C++20 you can use the new init-statement version of ranged for which was built for cases like this and would look like

    for (auto&& opt_vec =  returnStrings(); auto e : opt_vec.value())
        std::cout << e << " ";