mardi 29 septembre 2015

Unique Template Class without __LINE__ or __COUNTER__ Macros

First, let me start with what I'm trying to do. I'm working on a library that makes embedding a Python interpreter in C++ code a bit easier, and I'd like to leverage some C++11 features. I'm using std::functions quite heavily, which is a problem since Python makes heavy use of classic function pointers.

I've been using fredbaba's solution found at http://ift.tt/1h79SUZ

which may not be a good idea, but the reasoning seems sound; for every std::function you'd like a pointer too, you need to create some class or struct with a static function that invokes the std::function of interest, and any class function pointers can point to the static function.

However, that means you've got to ensure every struct created is unique; the poster from that thread uses a unique integer as an identifier, which is cumbersome. In my code I use the LINE macro (COUNTER never seems to work), but that of courses forces me to put everything in one file to avoid line number conflicts.

I've found similar questions asked but none of them really do it; in order for this to work the identifier has to be a compile time constant, and many of the solutions I've found fail in this regard.

Is this possible? Can I cheat the system and get pointers to my std::functions? If you're wondering why I need to... I take a std::function that wraps some C++ function, capture it in yet another function, then store that in a std::list. Then I create a function pointer to each list element and put them in a Python Module I create.

// Store these where references are safe
using PyFunc = std::function<PyObject *(PyObject *, PyObject *)>;
std::list<PyFunc> lst_ExposedFuncs;

...

// Expose some R fn(Args...){ ... return R(); }
template <size_t idx, typename R, typename ... Args>
static void Register_Function(std::string methodName, std::function<R(Args...)> fn, std::string docs = "")
{
    // Capture the function you'd like to expose in a PyFunc
    PyFunc pFn = [fn](PyObject * s, PyObject * a)
    {
        // Convert the arguments to a std::tuple
        std::tuple<Args...> tup;
        convert(a, tup);

        // Invoke the function with a tuple
        R rVal = call<R>(fn, tup);

        // Convert rVal to some PyObject and return
        return alloc_pyobject(rVal);
    };

    // Use the unique idx here, where I'll need the function pointer
    lst_ExposedFunctions.push_back(pFn);
    PyCFunction fnPtr = get_fn_ptr<idx>(lst_ExposedFunctions.back());
}

From there on I actually do something with fnPtr, but it's not important.

Is this crazy? Can I even capture a function like that?

John

Aucun commentaire:

Enregistrer un commentaire