Search code examples
c++boost-lambda

Boost lambda with shared_ptr


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.


Solution

  • 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>);
    }