[C++-sig] strange behavior with respect to numeric and Booleanoverloads
troy d. straszheim
troy at resophonic.com
Wed Mar 18 18:00:19 CET 2009
So, this isn't just a bool-int issue, you can get the same thing with
int and double:
std::string takes_bool(bool b) { return "bool"; }
std::string takes_int(int b) { return "int"; }
std::string takes_double(double b) { return "double"; }
BOOST_PYTHON_MODULE(overload_resolution)
{
def("bid", takes_bool);
def("bid", takes_int);
def("bid", takes_double);
def("bdi", takes_bool);
def("bdi", takes_double);
def("bdi", takes_int);
}
In [11]: its_an_int = 3
In [12]: bid(its_an_int)
Out[12]: 'double'
In [13]: bdi(its_an_int)
Out[13]: 'int'
In [14]: bid(True)
Out[14]: 'double'
The current rule for overload resolution are simply 'first match in
reverse order of registration'. You could relatively easily make this
'first match in forward order of registration'. The library currently
has no notion of one function being a better match than another, for a
given set of arguments. It looks like it would be interesting enough to
implement, but it isn't clear what those rules would be or if the
runtime cost would be worth it. For instance, this situation:
void fn_di(double, int);
void fn_id(int, double);
def("f", fn_di);
def("f", fn_id);
>>> f(3,3)
In C++, of course, that's a compile-time error. In python, would you
check all overloads for equally-good matches, and if so, throw some kind
of ambiguous_function_call exception?
Maybe somebody else has more ideas on this. I think you could tighten
up the automatic conversion rules (like the patch below does for int and
bool), so that one would have to clarify at the call site which function
you're calling:
>> f(float(3), 3)
this seems the most practical to me at the moment. It would break a
bunch of python code , but by adding casts, the old python code could be
made to work with boost.python bindings pre- and post- this change.
-t
troy d. straszheim wrote:
> I have a quasi-fix for this to the library itself, (see diff below)
> buuut it breaks a certain case: if you have a wrapped c++ function that
> takes a bool, and you try to pass it an int, you get a
>
> ArgumentError: Python argument types in
> builtin_converters_ext.rewrap_const_reference_bool(int)
> did not match C++ signature:
> rewrap_const_reference_bool(bool)
>
> so you have to call the function with an explicit cast to bool:
>
> c++:
>
> void takes_a_bool(bool b) { ... };
>
> def("py_takesbool", takes_a_bool);
>
> py:
>
> py_takesbool(bool(33))
>
> to get things to work. This breaks a lot of tests, I'm digging further.
>
>
> Index: converter/builtin_converters.cpp
> ===================================================================
> --- converter/builtin_converters.cpp (revision 51812)
> +++ converter/builtin_converters.cpp (working copy)
> @@ -99,8 +99,13 @@
> if (number_methods == 0)
> return 0;
>
> - return (PyInt_Check(obj) || PyLong_Check(obj))
> - ? &number_methods->nb_int : 0;
> + return (
> +#if PY_VERSION_HEX >= 0x02040000
> + !PyBool_Check(obj) &&
> +#endif
> + (PyInt_Check(obj) || PyLong_Check(obj)))
> +
> + ? &number_methods->nb_int : 0;
> }
> static PyTypeObject const* get_pytype() { return &PyInt_Type;}
> };
> @@ -135,7 +140,11 @@
> if (number_methods == 0)
> return 0;
>
> - return (PyInt_Check(obj) || PyLong_Check(obj))
> + return (
> +#if PY_VERSION_HEX >= 0x02040000
> + !PyBool_Check(obj) &&
> +#endif
> + (PyInt_Check(obj) || PyLong_Check(obj)))
> ? &py_object_identity : 0;
> }
> static PyTypeObject const* get_pytype() { return &PyInt_Type;}
> @@ -226,7 +235,11 @@
> {
> static unaryfunc* get_slot(PyObject* obj)
> {
> +#if PY_VERSION_HEX >= 0x02040000
> + return obj == Py_None || PyBool_Check(obj) ? &py_object_identity : 0;
> +#else
> return obj == Py_None || PyInt_Check(obj) ?
> &py_object_identity : 0;
> +#endif
> }
>
> static bool extract(PyObject* intermediate)
> _______________________________________________
> Cplusplus-sig mailing list
> Cplusplus-sig at python.org
> http://mail.python.org/mailman/listinfo/cplusplus-sig
More information about the Cplusplus-sig
mailing list