jhacsonmeza · GitHub

Thank you for the detailed reply!

First, it looks like the tests are failing even with the current state. In Python, when you define an equality method but not a hash method, the object automatically becomes unhashable. So we'd need to define __hash__ for sensor_t and data_t, e.g.

    .def("__hash__",
         [](const sensor_t& a) { return std::hash<colmap::sensor_t>()(a); });

As for the MakeDataclass, which classes do not have an equality operator? We could have a fallback that checks equality of the python dict (slower but ok):

#include <type_traits>
template<typename T, typename = void>
struct has_equality_operator : std::false_type {};
template<typename T>
struct has_equality_operator<T, std::void_t<decltype(std::declval<T&>() == std::declval<T&>())>> : std::true_type {};
template<typename T, typename = void>
struct has_less_than_operator : std::false_type {};
template<typename T>
struct has_less_than_operator<T, std::void_t<decltype(std::declval<T&>() < std::declval<T&>())>> : std::true_type {};
template<typename T, typename = void>
struct is_hashable : std::false_type {};
template<typename T>
struct is_hashable<T, std::void_t<decltype(std::hash<T>{}(std::declval<T>()))>> : std::true_type {};
template <typename T, typename... options>
void MakeDataclass(py::classh<T, options...> cls,
                   const std::vector<std::string>& attributes = {}) {
    // ...
    if constexpr (has_equality_operator<T>::value) {
        cls.def(py::self == py::self);
        if constexpr (is_hashable<T>::value) {
            cls.def("__hash__", [](const T& self) { return std::hash<T>()(self); });
        } else {
            cls.attr("__hash__") = py::none();
        }
    } else {
        cls.def("__eq__", [attributes](const T& self, const py::object& other) {
            if (!py::isinstance<T>(other)) {
                return false;
            }
            py::dict self_dict = ConvertToDict(self, attributes, true);
            py::dict other_dict = ConvertToDict(other.cast<T>(), attributes, true);
            return self_dict.equal(other_dict);
        });
        cls.attr("__hash__") = py::none();
    }
    if constexpr (has_less_than_operator<T>::value) {
        cls.def(py::self < py::self);
    }
}

(not tested)

Read the original on github.com ↗