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

David Abrahams dave at boost-consulting.com
Sat May 3 03:05:44 CEST 2003


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

> Hi,
>
> I have used boost libraries to wrap a large c++ library and it has worked
> very well.
>
> However, I stumbled on the issue of long long conversion to class problem.
> The problem has been reduced to the minimum code below.
>
> I would like to expose to python a class that has constructors from int and
> long long unsigned int among others:
>
> class Y {
>   public:
>     Y() : y(0L) { }
>     Y(int y) : y(y) { }
>     Y(long long unsigned int y) : y(y) { }
>     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;
> };
>
> I use boost thus:
>
> #include <boost/python/module.hpp>
> #include <boost/python/def.hpp>
>
> #include <boost/python.hpp>
> #include <hello.h>
>
> using namespace boost::python;
>
> BOOST_PYTHON_MODULE(hello)
> {
>     class_< Y >("Y", init<  >())
>         .def(init< int >())
>         .def(init< long long unsigned int >())
>         .def(init< const Y & >())
>         .def_readwrite("y", &Y::y)
>         .def("__int__", &Y::operator int)
>     ;
>
>     implicitly_convertible<int, Y>();
>     implicitly_convertible<long long unsigned int, Y>();
> }
>
> and use it in python thus:
>
> import hello
>
> x = hello.Y(4294967295)
> print x.y
> y = hello.Y(0xFFFFFFFFFFFFFFFF)
> print y.y
>
> However the code craps out:
>
> Traceback (most recent call last):
>   File "p.py", line 3, in ?
>     x = hello.Y(4294967295)
> OverflowError: long int too large to convert to int
>
> Why wouldn't it try yo convert to long long unsigned int before trying
> out int?

Because of the order of your implicitly_convertible<...> invocations.
Conversions to a C++ type (Y in this case) get tried in the order
they're registered.  I know; it's confusing since that's the opposite
of the way overloads work.

Are you sure you want the implicitly_convertible invocations?  You
don't need them in order to be able to compile and run the code above.
The only reason you would need them was if you wanted to be able to
pass a Python int or long directly to a wrapped C++ function accepting
a Y or Y const& argument.  If you *do* need that functionality, just
swap the order and everything will work.  However, the long long
conversion will mask the other one.

Incidentally, the following order also works:

    class_< Y >("Y", init<  >())
        .def(init< const Y & >())
        .def(init< int >())
        .def(init< long long unsigned int >())
        .def_readwrite("y", &Y::y)
        .def("__int__", &Y::operator int)
    ;

    implicitly_convertible<int, Y>();
    implicitly_convertible<long long unsigned int, Y>();

But this one breaks:

    class_< Y >("Y", init<  >())
        .def(init< const Y & >())
        .def(init< long long unsigned int >())
        .def(init< int >())
        .def_readwrite("y", &Y::y)
        .def("__int__", &Y::operator int)
    ;

    implicitly_convertible<int, Y>();
    implicitly_convertible<long long unsigned int, Y>();
    
That's because the constructor overloads get searched first (in
reverse order), then converters to the argument types get searched (in
forward order).

In your original example it was finding Y(const Y&) and looking for a
converter to the Y argument, finding the implicit converter for Python
Int -> Y, which is a good enough match to use with long values.

There's a lot of redundancy in all your declared constructors and
especially in the use of implicitly_convertible.  You might consider
starting with a minimal set of functionality (using unsigned long long
only) and seeing if you can get that to do what you want.

BTW,

        .def("__int__", &Y::operator int)

might be better written:

        .def(int_(self))

> I am seeking a behaviour where python int is converted to c++ int
> before constructing to c++ object Y, and python long is converted
> to c++ long long unsigned int before constructing to c++ object Y.

That might be difficult.  Guido and the lads are making it
increasingly difficult to detect a difference between Python int and
Python long, and plan to erase the distinction altogether soon.

Do you really need to handle the cases differently?

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com





More information about the Cplusplus-sig mailing list