2

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 https://stackoverflow.com/a/18422878

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

Community
  • 1
  • 1
John Joseph
  • 115
  • 2
  • 6
  • You can tag with types instead of numbers. As in `Register_Function("MyMethod", ...);` It's usually easier to come up with a unique type name than with a unique number. Note that you don't actually need to define `MyMethod_tag` - the elaborate type specifier doubles as a forward declaration, which is all that's needed. – Igor Tandetnik Sep 29 '15 at 14:15
  • That's an interesting solution and I may go with it. It seems a little verbose, but I guess an advantage is that you can encode some information into the name of the tag struct. Thanks! – John Joseph Sep 29 '15 at 14:51
  • Here's an example of what Igor's talking about... I think. http://ideone.com/zLYETM – John Joseph Sep 29 '15 at 15:53

1 Answers1

1

I do something vaguely similar for a similar use case (actually a class factory for use with a JNI). My technique is to use a template struct on an unsigned with a specialisation for 0: Each struct contains a function - you could adapt this to a static member for which a pointer would be valid. I also show how you could call a function foo with a parameter dependent on a particular specialisation (not sure you need this, but included just in case).

extern bar* foo(const unsigned& id); // The function that gets called

template<unsigned N> struct Registrar
{
    static bar* func()
    {
        return foo(N - 1);
    }

private:
    Registrar<N - 1> m_next; // Instantiate the next one.
};

template<> struct Registrar<0> // To block the recursion
{
};

namespace
{
    Registrar</*ToDo - total number here*/> TheRegistrar;
}

TheRegistrar is pretty much a metasyntactic variable which ensures that a given number of specialisations, and hence static functions are created.

(For various technical reasons I have to instantiate my templates in reverse order: if you don't need that then you can adjust accordingly.)

I imagine it's the interplay between func and foo that you'll need to adapt to your needs. Each N, of course, is that compile-time constant that you seek.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • Hmm, so when you declare TheRegistrar you hard code the number of unique templates you'd like? I can see this working.... I may go with Igor's answer since it allows me to encode some information in the method tag, and it's a little more applicable to my situation. Still, I'd be curious to see an example of how this applies to multiple functions. I'll vote you up, and if no one else answers the green checkmark is yours! – John Joseph Sep 29 '15 at 14:49