Search code examples
c++metaprogrammingboost-mplboost-function

Delegating to boost::function with arbitrary signature


I'm trying to create something like a boost::function, but with an extra 'smart handle' tucked inside, which controls the lifetime of a resource the functions needs to execute correctly.

If I didn't need the function signature to be completely generic, this would be easy. I would just create a functor with the correct signature, and keep a boost::function and the handle as members:

class library_function
{
public:
    library_function(
        library_handle handle,
        boost::function<result_type(arg1_type, arg2_type)> function)
        :
    m_handle(handle),
    m_function(function)
    {}

    typename result_type operator()(arg1_type arg1, arg2_type arg2)
    {
        return m_function(arg1, arg2);
    }

private:
    boost::function<result_type(arg1_type, arg2_type)> m_function;
    library_handle m_library;
};

However, I do need generic signatures. The code below is as close as I've got but gets a compile error, presumably, because I'm not able to unpack a list of arguments like this:

template<typename Signature>
class library_function
{
public:
    library_function(
        library_handle handle,
        boost::function<result_type(arg1_type, arg2_type)> function)
        :
    m_handle(handle),
    m_function(function)
    {}

    typename result_type operator()(arg1_type arg1, arg2_type arg2)
    {
        return m_function(arg1, arg2);
    }

    // I don't think I can declare the 'params' like this ...
    typename boost::function_types::result_type<Signature>::type operator()(
        boost::function_types::parameter_types<Signature> params)
    {
        return m_function(params); // ... nor unpack them like this
    }

private:
    boost::function<Signature> m_function;
    library_handle m_library;
};

I think params is an MPL list, so what I've actually done is declare a call operator with a single MPL-list parameter. My MPL-foo is not good. Is there a way to convert the list to a legal definition of multiple function paramters?

Alternatively, is there a way to get boost::function to accept this single MPL-list and unpack it into its, possibly multi-parameter callable?


For those who are interested, the 'smart handle' is a Windows DLL from which a function had been loaded by name (GetProcAddress). The handle will free the DLL when it's destroyed but that mustn't happen while anyone still wants to call the function. Hence embedding it in the callable.


Solution

  • For plain function, you can define the library_function as:

    template<typename Signature>
    class library_function
    {
    public:
        library_function(
            library_handle lib, Signature* library_function)
            :
        m_library(lib),
        m_function(library_function)
       {}
    
        operator Signature*() const { return m_function; }
    
    private:
       library_handle m_library;
       Signature* m_function;
    };
    

    The trick is operator Signature*() conversion operator, which allows the compiler fallback to the plain function m_function when you call with library_function.

    And you can add a helper function like:

    template<typename Signature>
    boost::function<Signature> make_library_function(library_handle library, Signature* f)
    {
        return library_function<Signature>(library, f);
    }
    

    Since boost::function then manages a copy of library_function, the 'smart handle' is managed as well.