pybind / pybind11

Seamless operability between C++11 and Python
https://pybind11.readthedocs.io/
Other
15.34k stars 2.07k forks source link

Unable to use bind_vector for types with unusual comparison operators #1470

Open mika-fischer opened 6 years ago

mika-fischer commented 6 years ago

Issue description

When a type has operator== defined, but it returns something other than bool or something that can be converted to bool, the detection logic in container_traits<T>::test_comparable fails and returns true when it should return false. Then code gets instantiated in vector_if_equal_operator which then fails to compile.

It should additionally to the existence of operator== be checked whether the return value can be converted to bool. But my metaprogramming skills are not good enough to come up with a clean solution...

Reproducible example code

#include <pybind11/pybind11.h>
#include <pybind11/stl_bind.h>

template<typename T>
struct vec { T a; T b; };

template<typename T>
vec<bool> operator==(const vec<T>& l, const vec<T>& r) {
    return {l.a == r.a, l.b == r.b};
}

PYBIND11_MODULE(test, m) {
    pybind11::bind_vector<std::vector<vec<float>>>(m, "float_vec_vector");
}

The actual type for which I ran into this is cv::Mat from OpenCV. And I worked around it for now with:

namespace pybind11::detail {
    template<> struct is_comparable<cv::Mat> : std::false_type {};
}
mika-fischer commented 6 years ago

The following works for me in container_traits in stl_bind.h:

template <typename T2> static decltype(std::declval<const T2 &>() == std::declval<const T2 &>()) test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>())*);
template <typename T2> static void test_comparable(...);
static constexpr const bool is_comparable = std::is_convertible<decltype(test_comparable<T>(nullptr)), bool>::value;