tags:

views:

223

answers:

3

I'm working on a resource management class and want to have the user provide a functor to a "ReleaseResource" method as part of the resource manager's constructor. From there when a resource is requested that functor will be provided as the deleter for the shared_ptr that I will be returning so that the appropriate method will be called when the resource is no longer used.

The problem I'm running into that this requires me to store the functor in my class, and I'm not entirely sure how to do that. Typically when using a functor you template the function like so:

template<class MyFunctor> MyMethod(MyFunctor f) {
    f();
}

Which is great if you intend to use the functor in the scope of that function, but since the template goes out of scope with the function I'm not sure how you would specify a variable of the appropriate type to store the functor for later use.

Can anyone point me in the right direction here?

A: 

Not sure if this would help, but be aware that boost::shared_ptr has constructor overrides which allow the user to include a custom de-allocation (and custom allocator, if desired). This might be sufficient for what you need (it's designed with that in mind, if I'm reading your use-case correctly).

Nick
I'm already aware of this, and am using it in the example above. What I need to know is how to store the parameter that you pass to it.
Toji
+5  A: 
template<class MyFunctor> MyMethod(MyFunctor f) {
    boost::function<void()> g = f;
    g();
}

The type you pass to boost::function is the function type. For example, int(bool, char) is the type of a function returning int and taking a bool and a char. That said, if you want to construct the shared_ptr right away, you don't need to store the functor somewhere (boost::function requires the new operator for that, even though for very small functors, it will use special tricks to only use stack allocation (small buffer optimization)):

template<class MyFunctor> MyMethod(MyFunctor f) {
    boost::shared_ptr<T> ptr(new T, f);
}

boost::function is part of tr1 and will be part of the next official C++ Standard. Example:

struct Manager {
    template<typename Deleter>
    Manager(Deleter d) 
        :deleter(d) {

    }

    boost::shared_ptr<Resource> allocate() {
        ...
        return boost::shared_ptr<Resource>(resource, deleter);
    }

private:
    boost::function<void(Resource *)> deleter;
};
Johannes Schaub - litb
Excellent! This is exactly what I was looking for. Thank you very much!
Toji
A: 

There are two ways, both of which biol down to templating the class.

template <MyFunctor>
class MyClass
{
   MyFunctor   func;
  public:
    MyClass(MyFunctor f) :func(f)
    { }


    MyMethod() 
   {
       func();
   }
}

This would require you to know the type of the functor. To avoid that, we can use a factory:

 template<MyFunctor>
 MyClass<MyFunctor>  MakeFunctorClass(MyFunctor f)
 {     
     return MyClass<MyFunctor>(f);       
 }

Alternately, since in all likelihood, most of the functor signature will be the same, with only a small part changing, we could use that:

template <MyType>
class MyClass
{
   typedef std::binary_function<MyType, MyType, bool>  MyFunctor;
   MyFunctor func;
  public:


    MyMethod(MyFunctor f) 
   {
       func = f;
       func();
   }
}

This makes usage a bit simpler:

 bool AreEqual(int, int); 
 MyClass<int> myc;
 myc.MyMethod(AreEqual);

at the expensive of a trickier definition (i.e., I don't guarantee that the binary_function typedef I gave will work)

James Curran
Except that this is not how 'binary_function' works. binary_function is a type-trait-giving-attribute, not an interface. it does not have an apply operator, so the statement 'func()' is invalid, even if you provide arguments.see other answer regarding boost::function, or tr1::function.
Aaron
Which is why I specifically said "I don't guarantee that the binary_function typedef I gave will work". I was pretty sure it wouldn't, but I knew there was a standard type that would.
James Curran