pybind11 icon indicating copy to clipboard operation
pybind11 copied to clipboard

[BUG]: Specifying return type `Eigen::Map<...>` in `PYBIND11_OVERRIDE_PURE` gives compilation error

Open sin3point14 opened this issue 7 months ago • 0 comments

Required prerequisites

  • [x] Make sure you've read the documentation. Your issue may be addressed there.
  • [x] Search the issue tracker and Discussions to verify that this hasn't already been reported. +1 or comment there if it has.
  • [ ] Consider asking first in the Gitter chat room or in a Discussion.

What version (or hash if on master) of pybind11 are you using?

2.11.1-2 (installed on ubuntu 24.04 via apt)

Problem description

According to the comment at https://github.com/pybind/pybind11/blob/bc4a66dff0464d0c87291b00a3688999fea5bedc/include/pybind11/eigen/matrix.h#L451-L453 pybind11 should support returning of Eigen::Map types from class methods, and it does work. However when I want to return a Map from a purely virtual function using PYBIND11_OVERRIDE_PURE it gives an error

Reproducible example code

#include <pybind11/pybind11.h>
#include <pybind11/eigen.h>
#include <pybind11/stl.h>

#include <Eigen/Eigen>

// typedef Eigen::MatrixXd T;
typedef Eigen::Map<Eigen::MatrixXd> T;

class A {
    virtual T f() = 0;
};


class PyA : A {
    virtual T f() override {
        PYBIND11_OVERRIDE_PURE(T, A, f);
    }
};

gives:

In file included from /usr/include/pybind11/attr.h:14,
                 from /usr/include/pybind11/detail/class.h:12,
                 from /usr/include/pybind11/pybind11.h:13,
                 from /home/sin3point14/random/cpp/pybind11-test/main.cpp:1:
/usr/include/pybind11/cast.h: In instantiation of ‘typename pybind11::detail::make_caster<T>::cast_op_type<typename std::add_rvalue_reference<_Tp>::type> pybind11::detail::cast_op(make_caster<T>&&) [with T = Eigen::Map<Eigen::Matrix<double, -1, -1> >; typename make_caster<T>::cast_op_type<typename std::add_rvalue_reference<_Tp>::type> = Eigen::Map<Eigen::Matrix<double, -1, -1> >; make_caster<T> = type_caster<Eigen::Map<Eigen::Matrix<double, -1, -1> >, void>; typename std::add_rvalue_reference<_Tp>::type = Eigen::Map<Eigen::Matrix<double, -1, -1> >&&]’:
/usr/include/pybind11/cast.h:1053:22:   required from ‘T pybind11::cast(const handle&) [with T = Eigen::Map<Eigen::Matrix<double, -1, -1> >; typename std::enable_if<((! std::is_base_of<detail::pyobject_tag, typename std::remove_reference<_Tp>::type>::value) && (! std::is_same<typename detail::remove_cvref<T>::type, _object*>::value)), int>::type <anonymous> = 0]’
/usr/include/pybind11/cast.h:1159:19:   required from ‘std::enable_if_t<((! std::is_base_of<pybind11::detail::pyobject_tag, typename std::remove_reference<_Tp>::type>::value) && pybind11::detail::negation<std::integral_constant<bool, (pybind11::detail::move_always<T>::value || pybind11::detail::move_if_unreferenced<T>::value)> >::value), T> pybind11::cast(object&&) [with T = Eigen::Map<Eigen::Matrix<double, -1, -1> >; std::enable_if_t<((! std::is_base_of<detail::pyobject_tag, typename std::remove_reference<_Tp>::type>::value) && detail::negation<std::integral_constant<bool, (detail::move_always<T>::value || detail::move_if_unreferenced<T>::value)> >::value), T> = Eigen::Map<Eigen::Matrix<double, -1, -1> >; typename std::remove_reference<_Tp>::type = Eigen::Map<Eigen::Matrix<double, -1, -1> >]’
/usr/include/pybind11/cast.h:1226:29:   required from ‘std::enable_if_t<pybind11::detail::negation<std::integral_constant<bool, (std::integral_constant<bool, (((std::is_reference< <template-parameter-1-1> >::value || std::is_pointer<_Tp>::value) && (! std::is_base_of<pybind11::detail::type_caster_generic, pybind11::detail::type_caster<typename pybind11::detail::intrinsic_type<T>::type> >::value)) && (! std::is_same<typename pybind11::detail::intrinsic_type<T>::type, void>::value))>::value || std::is_void<_Tp>::value)> >::value, T> pybind11::detail::cast_safe(pybind11::object&&) [with T = Eigen::Map<Eigen::Matrix<double, -1, -1> >; std::enable_if_t<negation<std::integral_constant<bool, (std::integral_constant<bool, (((std::is_reference< <template-parameter-1-1> >::value || std::is_pointer<_Tp>::value) && (! std::is_base_of<type_caster_generic, type_caster<typename intrinsic_type<T>::type> >::value)) && (! std::is_same<typename intrinsic_type<T>::type, void>::value))>::value || std::is_void<_Tp>::value)> >::value, T> = Eigen::Map<Eigen::Matrix<double, -1, -1> >; typename intrinsic_type<T>::type = Eigen::Map<Eigen::Matrix<double, -1, -1> >]’
/home/sin3point14/random/cpp/pybind11-test/main.cpp:17:9:   required from here
/usr/include/pybind11/cast.h:51:75: error: use of deleted function ‘pybind11::detail::eigen_map_caster<MapType>::operator MapType() [with MapType = Eigen::Map<Eigen::Matrix<double, -1, -1> >]’
   50 |     return std::move(caster).operator typename make_caster<T>::
      |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~            
   51 |         template cast_op_type<typename std::add_rvalue_reference<T>::type>();
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
In file included from /usr/include/pybind11/eigen.h:12,
                 from /home/sin3point14/random/cpp/pybind11-test/main.cpp:2:
/usr/include/pybind11/eigen/matrix.h:446:5: note: declared here
  446 |     operator MapType() = delete;
      |     ^~~~~~~~
/usr/include/pybind11/cast.h: In instantiation of ‘pybind11::detail::type_caster<T, SFINAE>& pybind11::detail::load_type(type_caster<T, SFINAE>&, const pybind11::handle&) [with T = Eigen::Map<Eigen::Matrix<double, -1, -1> >; SFINAE = void]’:
/usr/include/pybind11/cast.h:1037:14:   required from ‘pybind11::detail::make_caster<T> pybind11::detail::load_type(const pybind11::handle&) [with T = Eigen::Map<Eigen::Matrix<double, -1, -1> >; make_caster<T> = type_caster<Eigen::Map<Eigen::Matrix<double, -1, -1> >, void>]’
/usr/include/pybind11/cast.h:1053:35:   required from ‘T pybind11::cast(const handle&) [with T = Eigen::Map<Eigen::Matrix<double, -1, -1> >; typename std::enable_if<((! std::is_base_of<detail::pyobject_tag, typename std::remove_reference<_Tp>::type>::value) && (! std::is_same<typename detail::remove_cvref<T>::type, _object*>::value)), int>::type <anonymous> = 0]’
/usr/include/pybind11/cast.h:1159:19:   required from ‘std::enable_if_t<((! std::is_base_of<pybind11::detail::pyobject_tag, typename std::remove_reference<_Tp>::type>::value) && pybind11::detail::negation<std::integral_constant<bool, (pybind11::detail::move_always<T>::value || pybind11::detail::move_if_unreferenced<T>::value)> >::value), T> pybind11::cast(object&&) [with T = Eigen::Map<Eigen::Matrix<double, -1, -1> >; std::enable_if_t<((! std::is_base_of<detail::pyobject_tag, typename std::remove_reference<_Tp>::type>::value) && detail::negation<std::integral_constant<bool, (detail::move_always<T>::value || detail::move_if_unreferenced<T>::value)> >::value), T> = Eigen::Map<Eigen::Matrix<double, -1, -1> >; typename std::remove_reference<_Tp>::type = Eigen::Map<Eigen::Matrix<double, -1, -1> >]’
/usr/include/pybind11/cast.h:1226:29:   required from ‘std::enable_if_t<pybind11::detail::negation<std::integral_constant<bool, (std::integral_constant<bool, (((std::is_reference< <template-parameter-1-1> >::value || std::is_pointer<_Tp>::value) && (! std::is_base_of<pybind11::detail::type_caster_generic, pybind11::detail::type_caster<typename pybind11::detail::intrinsic_type<T>::type> >::value)) && (! std::is_same<typename pybind11::detail::intrinsic_type<T>::type, void>::value))>::value || std::is_void<_Tp>::value)> >::value, T> pybind11::detail::cast_safe(pybind11::object&&) [with T = Eigen::Map<Eigen::Matrix<double, -1, -1> >; std::enable_if_t<negation<std::integral_constant<bool, (std::integral_constant<bool, (((std::is_reference< <template-parameter-1-1> >::value || std::is_pointer<_Tp>::value) && (! std::is_base_of<type_caster_generic, type_caster<typename intrinsic_type<T>::type> >::value)) && (! std::is_same<typename intrinsic_type<T>::type, void>::value))>::value || std::is_void<_Tp>::value)> >::value, T> = Eigen::Map<Eigen::Matrix<double, -1, -1> >; typename intrinsic_type<T>::type = Eigen::Map<Eigen::Matrix<double, -1, -1> >]’
/home/sin3point14/random/cpp/pybind11-test/main.cpp:17:9:   required from here
/usr/include/pybind11/cast.h:1018:19: error: use of deleted function ‘bool pybind11::detail::eigen_map_caster<MapType>::load(pybind11::handle, bool) [with MapType = Eigen::Map<Eigen::Matrix<double, -1, -1> >]’
 1018 |     if (!conv.load(handle, true)) {
      |          ~~~~~~~~~^~~~~~~~~~~~~~
/usr/include/pybind11/eigen/matrix.h:445:10: note: declared here
  445 |     bool load(handle, bool) = delete;
      |          ^~~~
gmake[2]: *** [CMakeFiles/tsting.dir/build.make:76: CMakeFiles/tsting.dir/main.cpp.o] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/tsting.dir/all] Error 2
gmake: *** [Makefile:91: all] Error 2

If I don't use Map:

diff --git a/main.cpp b/main.cpp
index 266892a..e700e1d 100644
--- a/main.cpp
+++ b/main.cpp
@@ -4,8 +4,8 @@
 
 #include <Eigen/Eigen>
 
-// typedef Eigen::MatrixXd T;
-typedef Eigen::Map<Eigen::MatrixXd> T;
+typedef Eigen::MatrixXd T;
+// typedef Eigen::Map<Eigen::MatrixXd> T;
 
 class A {
     virtual T f() = 0;

it compiles fine

Is this a regression? Put the last known working version here if it is.

Not a regression

sin3point14 avatar Apr 17 '25 17:04 sin3point14