问题描述
如何在C ++ 11中重写以下代码以使用boost::optional
或boost::none
?
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;
}
解决方法
那么,您希望它返回值类型而不是指针吗?
由于object slicing,boost::optional
(或c ++ 17中的std::optional
)无法实现。对于值类型,您只能返回FooBase
所包含的信息,因此当您从一种派生类型进行转换时,您将丢失信息。
为此,您可以使用C ++ 17标准采用的另一种Boost类型:boost::variant
。这是类型安全的tagged union,可以在同一内存空间中保存一组类型之一。只需添加一个表示“无”的类型(C ++ 17中为std::monostate
的目的,Boost中为boost::blank
的目的),然后添加每个派生类型:
struct Bar1 { };
struct Bar2 { };
using Bar = boost::variant<boost::blank,Bar1,Bar2>;
然后您可以像这样重写函数:
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
}