How to rewrite with boost::optional in C++11?

161 views Asked by At

How do I rewrite the following code to use boost::optional or boost::none, in C++11?

std::unique_ptr<FooBase> find( std::string key)
{
    std::map<std::string, std::function<std::unique_ptr<FooBase>(void)> > m{
                       {"key1", [](){return std::make_unique<BarDerived>();} },
                       {"key2", [](){return std::make_unique<BarDerived1>();} } };
                                        
    auto it = m.find(key);
    if (it != std::end(m))
        return (it->second());  
    else 
        return nullptr;                                        

}
1

There are 1 answers

0
parktomatomi On

So, you want this to return a value type instead of a pointer?

That isn't possible with boost::optional (or std::optional in c++17), because of object slicing. For a value type, you can only return as much information as FooBase contains, so you'll lose information when you upcast from one of the derived types.

For this though, you can use another Boost type that got adopted by the C++17 standard: boost::variant. This is a type-safe tagged union that can hold one of a set of types in the same memory space. Just add a type to represent "none" (std::monostate's purpose in C++17, and boost::blank's purpose in Boost), and then add each derived type:

struct Bar1 { };
struct Bar2 { };
using Bar = boost::variant<boost::blank, Bar1, Bar2>;

Then you can rewrite your function like this:

Bar find( std::string key)
{
    std::map<std::string, std::function<Bar()> > m {
        {"key1", [](){return Bar1 {}; } },
        {"key2", [](){return Bar2 {}; } } 
    };
                                        
    auto it = m.find(key);
    if (it != std::end(m))
        return (it->second());  
    else 
        return { }; // default-constructs the first variant, in this case blank
}

https://godbolt.org/z/dcYevv