Boost logo

Boost Users :

From: Steven Watanabe (watanabesj_at_[hidden])
Date: 2008-08-09 15:51:30


AMDG

Scott McMurray wrote:
> On Fri, Aug 8, 2008 at 14:13, Jesse Perla <jlp400_at_[hidden]> wrote:
>
>> Is there any way to get a normal function pointer out of a boost::function
>> (with its state and potential bindings)? I want to have the option of
>> calling existing optimization routines that are not functor aware.
>>
> If all you can pass is a, say,
> double(*)(double), then you might be somewhat out of luck when it
> comes to nice solutions. You can always use global variables to pass
> the state, but those are obviously not nice.)

Here's a quick hack that hides the global variables:

#include <map>
#include <vector>
#include <boost/function.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/preprocessor/iteration/local.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>

template<class Sig, class Id>
struct function_holder;

#define BOOST_PP_LOCAL_MACRO(n) \
                                                                        \
template<class R BOOST_PP_ENUM_TRAILING_PARAMS(n, class T), class Id> \
struct function_holder<R(BOOST_PP_ENUM_PARAMS(n, T)), Id> { \
    static boost::function<R(BOOST_PP_ENUM_PARAMS(n, T))> impl; \
    static R function(BOOST_PP_ENUM_BINARY_PARAMS(n, T, t)) { \
        return(impl(BOOST_PP_ENUM_PARAMS(n, t))); \
    } \
}; \
                                                                        \
template<class R BOOST_PP_ENUM_TRAILING_PARAMS(n, class T), class Id> \
boost::function<R(BOOST_PP_ENUM_PARAMS(n, T))> \
function_holder<R(BOOST_PP_ENUM_PARAMS(n, T)), Id>::impl;

#define BOOST_PP_LOCAL_LIMITS (0, 10)
#include BOOST_PP_LOCAL_ITERATE()

template<class Sig, class Id, int Size>
struct function_pool {
    static std::map<Sig*, boost::function<Sig>*> allocated_functions;
    static std::vector<std::pair<Sig*, boost::function<Sig>*> >
free_functions;
    struct insert_free_function {
        template<class N>
        void operator()(const N&) const {
            free_functions.push_back(std::make_pair(
                &function_holder<Sig, boost::mpl::pair<Id, N> >::function,
                &function_holder<Sig, boost::mpl::pair<Id, N> >::impl));
        }
    };
    static void init() {
        boost::mpl::for_each<boost::mpl::range_c<int, 0, Size>
>(insert_free_function());
    }
    static Sig* allocate(const boost::function<Sig>& f) {
        std::pair<Sig*, boost::function<Sig>*> result =
free_functions.back();
        *result.second = f;
        allocated_functions.insert(result);
        free_functions.pop_back();
        return(result.first);
    }
    static void free(Sig* victim) {
        typename std::map<Sig*, boost::function<Sig>*>::iterator pos =
allocated_functions.find(victim);
        free_functions.push_back(*pos);
        allocated_functions.erase(pos);
    }
};

template<class Sig, class Id, int Size>
std::map<Sig*, boost::function<Sig>*> function_pool<Sig, Id,
Size>::allocated_functions;

template<class Sig, class Id, int Size>
std::vector<std::pair<Sig*, boost::function<Sig>*> > function_pool<Sig,
Id, Size>::free_functions;

#include <iostream>

struct pool : function_pool<void(int), pool, 10> {};

struct hello {
    void operator()(int) const {
        std::cout << "Hello, ";
    }
};

struct world {
    void operator()(int) const {
        std::cout << "World!" << std::endl;
    }
};

int main() {
    pool::init();
    void (*hello_function)(int) = pool::allocate(hello());
    void (*world_function)(int) = pool::allocate(world());

    hello_function(1);
    world_function(1);

    pool::free(hello_function);
    pool::free(world_function);
}

In Christ,
Steven Watanabe


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net