Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generalized exception translation for boost python

The current boost::python example for translating a specific C++ exception into python goes like this:

void translate (const MyException& e) {
   PyErr_SetString(PyExc_RuntimeError, e.what());
}

boost::python::register_exception_translator<MyException>(translate);

Unfortunately, this requires that we write a specific function for each of our exceptions. We tried to simplify this, by writing a generalized exception translator:

#include <boost/python.hpp>

// Generalized exception translator for Boost Python
template <typename T> struct GeneralizedTranslator {

  public:

    void operator()(const T& cxx_except) const {
      PyErr_SetString(m_py_except, cxx_except.what());
    }

    GeneralizedTranslator(PyObject* py_except): m_py_except(py_except) {
      boost::python::register_exception_translator<T>(this);
    }

    GeneralizedTranslator(const GeneralizedTranslator& other): m_py_except(other.m_py_except) {
      //attention: do not re-register the translator!
    }

  private:

    PyObject* m_py_except;

};

//allows for a simple translation declaration, removes scope problem
template <typename T> void translate(PyObject* e) {
  ExceptionTranslator<T> my_translator(e);
}

Would that bit of code work, you could wrap exceptions that implement "what()" like this:

BOOST_PYTHON_MODULE(libtest)
{
  translate<std::out_of_range>(PyExc_RuntimeError);
}

Unfortunately, it seems boost::python will call the "translation" code as a function inside "boost/python/detail/translate_exception.hpp" (line 61):

translate(e);

In our generalized exception handler this would be a call to GeneralizedTranslator::operator() and that will not work for g++, giving:

error: ‘translate’ cannot be used as a function

Is there a correct way to write this?

like image 787
André Anjos Avatar asked Aug 02 '11 08:08

André Anjos


1 Answers

You're passing the this pointer as the translate function, and this fails because a pointer to an object can't be called as a function. If you pass *this instead this should work (note that this will copy-construct the GeneralizedTranslator object). Or you can move the registration out of the constructor, and call

register_exception_translator<std::out_of_range>(GeneralizedTranslator<std::out_of_range>(PyExc_RuntimeError));
like image 148
interjay Avatar answered Oct 21 '22 17:10

interjay