2

I am trying to expose the C++ class with name aliasing to python using boost python.

struct Foo
{
  void hi() const { std::cout << "hi" << std::endl; }
};

BOOST_PYTHON_MODULE(Example)
{
  typedef Foo Bar;

  class_<Foo>("Foo")
    .def("hi", &Foo::hi)
  ;

  class_<Bar>("Bar")
    .def("hi", &Bar::hi)
  ;
}

The code works as expected except the annoying RuntimeWarning.

RuntimeWarning: to-Python converter for Foo already registered; second conversion method ignore

Adding Bar = Foo in python also works. But I need to keep the definitions in the same module. Is there a better way to achieve this?

2 Answers 2

3

I'd go with the "C++ equivalent to the Python Bar = Foo" approach that Ulrich mentions.

You can use boost::python::scope to get access to the current module and its attributes.

#include <boost/python.hpp>
#include <iostream>

namespace bp = boost::python;

struct Foo
{
    void hi() const { std::cout << "hi" << std::endl; }
};

BOOST_PYTHON_MODULE(Example)
{
    bp::class_<Foo>("Foo")
        .def("hi", &Foo::hi)
        ;

    bp::scope().attr("Bar") = bp::scope().attr("Foo");
}
Sign up to request clarification or add additional context in comments.

1 Comment

Wow. That's exactly what I am looking for. Thank you.
2

Since typedef only introduces an alias, your code just registers the same class under different names.

Suggestions:

  • Why would you want that anyway? Just register it once under its real name. As you mentioned, creating an alias in Python (again, why?) is easy.
  • If you just declared a baseclass and derived both Foo and Bar from it, you would have different types and the warning would vanish, too.
  • You could probably also write a C++ equivalent to the Python Bar = Foo, i.e. a simple assignment of an object to a name in the module namespace.

Given the feedback below that it's required to support legacy code, here's what I would do:

// same as above
struct Foo { ... };

// For legacy reasons, it is mandatory that Foo is exported
// under two names. In order to introduce new C++ types, we
// just derive from the original Foo. The approach using a
// typedef doesn't work because it only creates an alias but
// not an existing type.
struct FooType: Foo {};
struct BarType: Foo {};

BOOST_PYTHON_MODULE(Example)
{
  class_<FooType>("Foo")
    .def("hi", &FooType::hi)
  ;
  class_<BarType>("Bar")
    .def("hi", &BarType::hi)
  ;
}

3 Comments

Thanks for the suggestions. The dilemma comes from the fact that I couldn't change much on the legacy C++ class definitions. Also, I am creating a python module for user who wants everything is there with one single module load. However, I couldn't understand your last point. The C++ equivalent to the aliasing in Python should be typedef or using. They work well in pure C++. But I still need Bar to be defined in the Example module.
Yes and no. Using a typedef or using, you create an alias. However, both the original name and the alias refer to the same type. What you want is a different type, even though it should behave like alike. In other words, you want equality but not identity. I'll try to illustrate this part with example code.
What I need was actually aliasing, i.e., refer to the same type. Your technique also works, but I am still expecting some other tricks to achieve it via boost with minimal coding complexity.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.