Skip to content

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

Open
@sin3point14

Description

@sin3point14

Required prerequisites

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

// Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
// types but not bound arguments). We still provide them (with an explicitly delete) so that
// you end up here if you try anyway.
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

Metadata

Metadata

Assignees

No one assigned

    Labels

    triageNew bug, unverified

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions