Reputation: 31
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;
}
Upvotes: 2
Views: 174
Reputation: 4089
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
}
Upvotes: 1