3
\$\begingroup\$

I'm reworking PyCXX (C++ wrapper for Python).

I'm currently examining the following macro code, and wondering whether there is a way to write it using templates rather than macros.

If so, the question becomes: what is the best way to write it? (I personally favour a concise macro solution over an awkward template solution).

#define PYCXX_NOARGS_METHOD_NAME( NAME ) _callNoArgsMethod__##NAME
#define PYCXX_VARARGS_METHOD_NAME( NAME ) _callVarArgsMethod__##NAME
#define PYCXX_KEYWORDS_METHOD_NAME( NAME ) _callKeywordsMethod__##NAME

// - - -

#define PYCXX_DECLARE_METHOD( THIS_CLASS, METHOD_NAME, Ax, NAME_OF_THIS_STATIC_METHOD, ... ) \
    \
    static PyObject* NAME_OF_THIS_STATIC_METHOD( PyObject* _pyObj_caller, PyObject* _a, PyObject* _k ) \
    { \
        DBG_LINE( Ax << #NAME_OF_THIS_STATIC_METHOD << Ax ); \
        try \
        { \
            Py::PythonClassInstance* base_cxx_obj   = reinterpret_cast< Py::PythonClassInstance* >( _pyObj_caller ); \
            THIS_CLASS*              this_class_obj = reinterpret_cast< THIS_CLASS* >             ( base_cxx_obj->m_pycxx_object ); \
            Py::Object result{  (this_class_obj -> METHOD_NAME)(__VA_ARGS__)  }; /* __VA_ARGS__ uses _a and _k (see below) */ \
            return Py::new_reference_to( result.ptr() ); \
        } \
        catch( Py::Exception & ) \
        { \
            DBG_LINE( "! ! !  Exception in PYCXX_DECLARE_METHOD ! ! !" ); \
            return 0; \
        } \
    }

#define PYCXX_NOARGS_METHOD_DECL(   _class, name ) PYCXX_DECLARE_METHOD( _class, name, "  &  "     , PYCXX_NOARGS_METHOD_NAME(   name ) )
#define PYCXX_VARARGS_METHOD_DECL(  _class, name ) PYCXX_DECLARE_METHOD( _class, name, "  & &  "   , PYCXX_VARARGS_METHOD_NAME(  name ), Py::Tuple{_a} )
#define PYCXX_KEYWORDS_METHOD_DECL( _class, name ) PYCXX_DECLARE_METHOD( _class, name, "  & & &  " , PYCXX_KEYWORDS_METHOD_NAME( name ), Py::Tuple{_a}, _k?Py::Dict{_k}:Py::Dict{} )

... and

#define PYCXX_ADD_METHOD( py_name, method_name, docs, flags ) \
    add_method( \
               #py_name, \
               (PyCFunction)method_name, \
               flags, \
               docs \
               )

#define PYCXX_ADD_NOARGS_METHOD(   py_name, name, docs )  PYCXX_ADD_METHOD( py_name, PYCXX_NOARGS_METHOD_NAME(   name ), docs, METH_NOARGS )
#define PYCXX_ADD_VARARGS_METHOD(  py_name, name, docs )  PYCXX_ADD_METHOD( py_name, PYCXX_VARARGS_METHOD_NAME(  name ), docs, METH_VARARGS )
#define PYCXX_ADD_KEYWORDS_METHOD( py_name, name, docs )  PYCXX_ADD_METHOD( py_name, PYCXX_KEYWORDS_METHOD_NAME( name ), docs, METH_VARARGS | METH_KEYWORDS )

It is used in a class to expose certain methods to Python:

Py::Object new_style_class_func_noargs( void )
{
    std::cout << "new_style_class_func_noargs Called."           << std::endl << std::endl;
    std::cout << "value ref count " << m_value.reference_count() << std::endl << std::endl;
    return Py::None();
}
PYCXX_NOARGS_METHOD_DECL( new_style_class, new_style_class_func_noargs )

static void init_type(void)
{
    :
    PYCXX_ADD_NOARGS_METHOD(    func_noargs , new_style_class_func_noargs,  "docs for func_noargs"  );
}

The reason for this architecture is that Python can only fit "extern C" style functions into its tables. But this code is attempting to run C++ instance member functions.

Hence it has to trampoline off a static member function (as a static member function type casts to an "extern C" style function).

And we require a separate static member function for each method we wish to expose.

Is there any way to use templates to accomplish this?

\$\endgroup\$

closed as off-topic by Emily L., RubberDuck, janos, Marc-Andre, TheCoffeeCup Jan 14 '15 at 19:27

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Questions containing broken code or asking for advice about code not yet written are off-topic, as the code is not ready for review. After the question has been edited to contain working code, we will consider reopening it." – Emily L., RubberDuck, janos, Marc-Andre, TheCoffeeCup
If this question can be reworded to fit the rules in the help center, please edit the question.

  • 2
    \$\begingroup\$ Possibly off topic for being a "Give me the code!"-question. \$\endgroup\$ – nwp Nov 12 '14 at 9:48
  • \$\begingroup\$ @nwp, No. I'm asking for alternative design patterns. \$\endgroup\$ – P i Nov 12 '14 at 13:08
  • 3
    \$\begingroup\$ I believe that this question is off-topic. The post is not about reviewing the posted code but rather a "How do I do X?" question which is better suited for stackoverflow.com. \$\endgroup\$ – Emily L. Jan 14 '15 at 15:14
  • \$\begingroup\$ I am voting to leave open. make this as simple as possible --> If so, the question becomes: what is the best way to write it? \$\endgroup\$ – Malachi Jan 14 '15 at 18:11
  • \$\begingroup\$ I remember when I originally posted I couldn't see any other route, so it seemed fair enough to invite a review. However, subsequently I started to find different ways of doing it, and maybe it has drifted off topic as a consequence. If it is of any interest, I have recently found a very clean solution here. (NOTE: one would have to follow the thread backwards a few posts to connect with this particular question). \$\endgroup\$ – P i Jan 14 '15 at 22:01
1
\$\begingroup\$

Surprisingly (to me at any rate) there is a template solution.

It appears that it is possible to do:

template<FuncSignature funcPointer>
myFunc(){...}

And later:

x = myFunc<&MyClass::MyMethod>

You can pick up the trail here: https://stackoverflow.com/questions/26934036/coding-static-to-instance-method-trampoline-function-with-templates

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.