使用shared_ptr提升lambda
Boost lambda with shared_ptr
如果我有一个名为base的多态基类,以及从base继承的类Derived1和Derived2。然后,我可以使用boost::lambda来创建某种类型的工厂。类似于:
typedef boost::function<Base *()> Creator;
std::map<std::string,Creator> map1;
map1["Derived1"] = boost::lambda::new_ptr<Derived1>();
map1["Derived2"] = boost::lambda::new_ptr<Derived2>();
(这不是真正的代码,我只是想说明问题。(
这是可行的,因此我可以使用字符串在映射中进行查找,然后调用lambda函数来实例化该类。一切都很好。
问题是它处理的是原始指针,我更喜欢使用智能指针(std::shared_ptr(。
所以如果我从:
typedef boost::function<Base *>() Creator;
至:
typedef boost::function<std::shared_ptr<Base> >() Creator;
然后我就被困在这里了。我曾尝试将boost::lambda::bind与boost:;lambda::new_ptr结合使用,但我运气不佳,无法克服编译错误。(大量与模板相关的错误输出。(
我已经在StackOverflow中检查了其他类似的消息,使用boost::bind和boost::lambda::new_ptr返回shared_ptr构造函数是关闭的,但如果我尝试应用它的解决方案,我会得到上面提到的模板错误。
如果有帮助的话,我很乐意提供示例代码和实际错误,但希望以上信息足够了。我在GCC 4.6上使用boost 1.47.0,在Fedora 15上使用4.7快照。
class Base {
public:
virtual ~Base() = 0;
};
Base::~Base() {}
class Derived1 : public Base {};
class Derived2 : public Base {};
typedef boost::shared_ptr<Base> BasePtr;
typedef boost::function<BasePtr()> Creator;
template <typename T>
Creator MakeFactory()
{
namespace la = boost::lambda;
return la::bind(
la::constructor<BasePtr>(),
la::bind(la::new_ptr<T>()));
}
int _tmain(int argc, _TCHAR* argv[])
{
std::map<std::string,Creator> map1;
map1["Derived1"] = MakeFactory<Derived1>();
map1["Derived2"] = MakeFactory<Derived2>();
BasePtr p1 = map1["Derived1"]();
BasePtr p2 = map1["Derived2"]();
return 0;
}
然而,既然你可以写:,为什么还要麻烦呢
template <typename T>
BasePtr MakeFactoryImpl()
{
return BasePtr(new T());
}
template <typename T>
Creator MakeFactory()
{
return Creator(&MakeFactoryImpl<T>);
}
这是一个常见的问题。两种类型是相关的(在您的案例中是通过继承(,这并不意味着模板与这两种类型的实例化保持相同的关系。
解决方案是始终返回shared_ptr<Base>
,因为它可以同时包含指向Base
或任何派生类型的指针,这将在语义上与当前版本兼容(即,在这两个版本中,调用者都会获得指向Base
的(智能(指针。
顺便说一句,我会避免从工厂返回shared_ptr
,因为您正在强制所有用户选择智能指针。我更喜欢返回原始指针(用户可以选择,但在某些情况下很危险(或unique_ptr
甚至auto_ptr
,它们是安全的,并且仍然允许用户选择不同的机制(即,如果您的函数返回auto_ptr
,则用户仍然可以通过执行shared_ptr<Base> p( f().release() );
来使用shared_ptr
,而相反是不可能的(由shared_ptr
管理的内存不能被释放以在不同的智能指针中使用。
这种快速而肮脏的返回类型适配器不仅适用于将返回类型从Derived*
转换为Base*
,而且适用于任何可转换类型之间的转换。为了简单起见,函数对象不接受任何参数。使用C++11可变模板,应该可以很容易地添加任意参数处理。请随意以任何方式对此进行改进。
template <typename ToType>
class return_type_adapter
{
template <typename toType>
class return_type_adapter_impl_base
{
public:
virtual toType call() = 0;
};
template <typename toType, typename Func>
class return_type_adapter_impl : public return_type_adapter_impl_base<toType>
{
public:
return_type_adapter_impl (Func func) : func(func) {}
toType call() { return toType(func()); }
private:
Func func;
};
boost::shared_ptr<return_type_adapter_impl_base<ToType> > impl_base;
public:
ToType operator() () { return impl_base->call(); }
template <typename Func>
return_type_adapter (Func func) :
impl_base(new return_type_adapter_impl<ToType, Func>(func)) {}
};
map1["Derived1"] = boost::lambda::bind(
boost::lambda::constructor<boost::shared_ptr<Base>>(),
boost::lambda::bind(
boost::lambda::new_ptr<Derived1>()));
map1["Derived2"] = boost::lambda::bind(
boost::lambda::constructor<boost::shared_ptr<Base>>(),
boost::lambda::bind(
boost::lambda::new_ptr<Derived2>()));
但老实说,在这种复杂程度上,再使用boost lambda也没有意义了。一个更简单的解决方案:
template<typename DerivedType>
boost::shared_ptr<Base> makeDerived() {
return boost::shared_ptr<Base>(new DerivedType);
}
[...]
map1["Derived1"] = makeDerived<Derived1>;
map1["Derived2"] = makeDerived<Derived2>;
- 在提升multi_index容器中,是否定义了"default index"?
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 提升 ASIO 无法识别计时器对象
- 可组合的lambda/std::函数与std::可选
- 提升精神:解析布尔表达式并简化为规范范式
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 如何克服提升精神AST混乱
- 如何建立使用模板函数的lambda函数的尾部返回类型
- 如何将lambda作为模板类的成员函数参数
- C++从其他 constexpr 创建 lambda 不能按顺序执行 Constexpr
- 如何将提升regex_replace与 lambda 函数一起使用
- 提升回显服务器示例并在 lambda 中捕获此和 shared_from_this()
- 提升预定义为带有参数的全局 lambda 的变体访问者
- 提升范围不适用于 C++1y 初始化捕获可变 lambda
- 如何在提升 lambda 中使用下标运算符
- 将提升 lambda 与复合表达式结合使用
- 如何使用提升 lambda 对集合中的每个元素调用方法?
- 提升lambda示例
- 使用shared_ptr提升lambda
- C++:使用提升 lambda 获取 std::tr1::unordered_map 中的最大值