[C++-sig] Re: long long unsigned issue...

David Abrahams dave at boost-consulting.com
Thu May 29 15:09:50 CEST 2003

"Milind Patil" <milind_patil at hotmail.com> writes:

> Coming to issue with long_ conversion that I have had.
> I constructed a toy example to experiment with the long_
> conversion issue. Recapping, given the class
> class Y {
>    public:
>      Y() : y(0L) { }
>      Y(int y) : y(y) { }
>      Y(long long unsigned int y) : y(y) { }
>      Y(int s, const Y & y) : y(y << s) { }
>      Y(Y const& rhs) : y(rhs.y) { }
>      virtual ~Y() { }
>      operator int() const { return y; }
>      void operator=(Y const& y) {
>          this->y = y.y;
>      }
>      long long unsigned int y;
>  };

My point is that this is a *very* big toy, with lots of constructors
which look like they could potentially contend for the same input
arguments.  Can't you reduce the problem you're having a little bit

> that I would like to wrap to python:
> {
>     class_< Y, Y_Wrapper >("Y", init<  >())
>         .def(init< const Y & >())
>         .def(init< int, const Y & >())
>         .def(init< int >())
>         .def(init< long long unsigned int >())
>         .def_readwrite("y", &Y::y)
>         .def("__int__", &Y::operator int)
>      ;
>      impilcitly_convertible<int, Y>();
> }
> The implicitly_converitble above is to facilitate conversion
> to Y(int, &Y) for python x = hello.Y(2, 24) etc.
> I wanted to add conversion capability from and to python
> long_ 

Do you need *implicit* conversion capability?  Remember that implicit
conversions are generally un-Pythonic.

> which was possible via a wrapper class (again, something
> that pyste originally generated):
>  namespace {
>  struct Y_Wrapper: Y {
>      Y_Wrapper (PyObject* self_) : Y(), self(self_) {}
>      Y_Wrapper (PyObject* self_, int y) : Y(y), self(self_) {}
>      Y_Wrapper (PyObject* self_, long long unsigned int y) : Y(y), self(self_) {}
>      Y_Wrapper (PyObject* self_, int s,  const Y& y) : Y(s,y), self(self_) {}
>      Y_Wrapper (PyObject* self_, const Y& y) : Y(y), self(self_) {}
>      Y_Wrapper (PyObject* self_, boost::python::long_ y) : Y(0), self(self_) {printf("hello
> long_");}
>      PyObject* self;
>  };
> }
> and adding
>          .def(init< long_ >())
> to module definition.
> So far so good. With your recent fixes it works perfectly for python
> construction of Y from long eg. x = hello.Y(4294967295) -- this is
> the type b constructor in the constructors I enumerated above. But
> if I want to construct signals of given width, then I would have x =
> signal(127,0, 4294967295), or x = hello.Y(127, 4294967295) for the
> toy example. This statement will cause a runtime exception fault
> saying that "OverflowError: long int too large to convert to int",
> probably because it is trying construct to Y(int s, const Y& y) and
> does not know how to make long_ to Y! My question here was :
> Now that we have a long_ to Y_Wrapper constructor
> and that class_ Y has Y_Wrapper as one of the bases

You got that backwards.  Y is the base of Y_Wrapper.

> is it possible to use an implicity_convertible<long_, Y_Wrapper>();
> to be able to facilitate the conversion?

No, precisely because Y_Wrapper is not a base of Y.

The right solution to this problem is to provide for something Ralf
has been requesting for some time:  the ability to inject new
constructors into a class, just the way we can inject methods that
aren't built from member functions.  Something like:

Y Y_from_pylong(long_ y)
    return Y(extract<unsigned long long>(y));

       .def("__init__", constructor(Y_from_pylong))

> I am not comletely dead in water:
> I have added a .def(init<int, long_>) to module definition and a
> Y_Wrapper(PyObject* self_, int s,  boost::python::long_ y)
> to Y_Wrapper to get around the inability to do a
> implicitly_convertible<long_ Y_Wrapper>() to effect the conversion.
> This works for me right now. I once again thank you for helping me
> with the issue I had.
> If you have read so far, I had some more observations as a user:
> Some of the use case scenarios for boost python are:
> a) Expose C++ classes as python classes alone. User will not derive
>     from the exposed classes.
> b) Expose C++ classes as derivable classes in python.

a and b are equivalent as far as the library is concerned.

> c) Embedded scenarios with above two where it goes c++ to python to c++
>     back etc.

Anything with, e.g., overridable virtual functions fits that picture.
It has nothing to do with embedding AFAICT... or am I missing

> d) Expose C++ classes as derived or as convertible to python types (numeric,
>     tuples, str etc.)

Case d can be combined with any of the other cases.

> My particular use case is a) and d). And there is adequate
> documentation/information to be able to be able to figure it out but it is
> difficult. Perhaps the document can handle c) and d) a little more?

I'm confused.  Why do you want more info on c) if you don't use
Boost.Python that way?

> Anything I can help with?

Better support for your use cases has to come from two ends:
implementation and documentation.  Part of the reason that d) isn't
better-documented is that its current implementation is too
complicated and low-level to expose to users.  All of this can be
fixed by funding some library development.

Dave Abrahams
Boost Consulting

More information about the Cplusplus-sig mailing list