使用shared_ptr增强lambda

发布于 2024-12-01 01:05:25 字数 1139 浏览 6 评论 0原文

如果我有一个名为 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 快照。

If I have a polymorphic base class called Base as well as classes Derived1 and Derived2 which inherit from Base. I can then use boost::lambda to create a factory of sorts. Something like:

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>();

(This isn't real code, I'm just trying to illustrate the problem.)

This works, so I can then do a lookup in the map using a string and then invoke the lambda function to instantiate that class. All good.

The problem with this is that it's dealing in raw pointers, I'd prefer to be using smart pointers (std::shared_ptr).

So if I change from:

typedef boost::function<Base *>() Creator;

to:

typedef boost::function<std::shared_ptr<Base> >() Creator;

Then I'm getting stuck from here. I've tried using boost::lambda::bind in conjunction with boost::lambda::new_ptr but I'm not having much luck, can't get past compilation errors. (Huge reams of template-related error output.)

I've checked other similar messages within StackOverflow, Using boost::bind and boost::lambda::new_ptr to return a shared_ptr constructor is close but if I try to apply its solution I get the template errors mentioned above.

I'm happy to provide sample code and the actual errors if it helps, but hopefully the above info is sufficient. I'm using boost 1.47.0 on GCC 4.6 as well as 4.7 snapshot on Fedora 15.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

生生漫 2024-12-08 01:05:25
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>);
}
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;
}

however, why go to the trouble when you could write:

template <typename T>
BasePtr MakeFactoryImpl()
{
    return BasePtr(new T());
}
template <typename T>
Creator MakeFactory()
{
    return Creator(&MakeFactoryImpl<T>);
}
緦唸λ蓇 2024-12-08 01:05:25

这是一个常见问题。两种类型相关(在您的情况下是通过继承)这一事实并不意味着具有这两种类型的模板的实例化保持相同的关系。

解决方案是始终返回 shared_ptr,因为它可以保存指向 Base 或任何派生类型的指针,这将在语义上与您当前的版本兼容(即在两个版本的调用者都会获得一个指向Base(智能)指针

顺便说一句,我会避免从工厂返回shared_ptr,因为你在强迫你的我更愿意返回一个原始指针(用户可以选择,但在某些情况下这是危险的)或一个 unique_ptr 甚至 auto_ptr< /code>,这是安全的,并且仍然允许用户选择不同的机制(即,如果您的函数返回 auto_ptr,用户仍然可以通过执行以下操作来使用 shared_ptr shared_ptrp( f().release() );,而相反的情况是不可能的(shared_ptr 管理的内存不能释放 用于不同的智能指针。

This is a common problem. The fact that two types are related (in your case by inheritance) does not imply that the instantiations of a template with those two types maintains the same relationship.

The solution is to return always shared_ptr<Base>, since it can hold both pointers to Base or any derived type, which will be semantically compatible with your current version (i.e. in both versions the caller gets a (smart)-pointer-to Base.

As an aside, I would avoid returning shared_ptr from a factory, as you are forcing your choice of smart pointer into all of your users. I would prefer to either return a raw pointer (the user can choose, but it is dangerous in some situations) or a unique_ptr or even auto_ptr, which are safe and still allow the user to choose a different mechanism (i.e. if your function returns an auto_ptr, the user can still use a shared_ptr by doing shared_ptr<Base> p( f().release() );, while the opposite is not possible (memory managed by a shared_ptr cannot be released to use in a different smart pointer.

冰火雁神 2024-12-08 01:05:25

这个快速而肮脏的返回类型适配器不仅适用于将返回类型从 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)) {}
};

This quick-and-dirty return type adapter is good not only for converting return types from Derived* to Base*, but between any convertible types. For simplicity, the function-object takes no arguments. With C++11 variadic templates it should be easy to add arbitrary argument handling. Feel free to improve on this in any way you wish.

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)) {}
};
殤城〤 2024-12-08 01:05:25
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>;
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>()));

But honestly, this is the level of complexity where it doesn't really make sense to use boost lambda any more. A simpler solution:

template<typename DerivedType>
boost::shared_ptr<Base> makeDerived() {
    return boost::shared_ptr<Base>(new DerivedType);
}
[...]

    map1["Derived1"] = makeDerived<Derived1>;
    map1["Derived2"] = makeDerived<Derived2>;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文