Skip to content

invalid abstract return type when wrapping operator overloading on an abstract base class #1487

@inducer

Description

@inducer

Issue description

It appears that execute_cast in pybind11's operators.h introduces an artificial requirement that the wrapped type be concrete and copyable (because execute_cast returns a plain instance).

pybind11/include/pybind11/operators.h:84:14: error: invalid abstract return type ‘Abstract’
     static B execute_cast(const L &l, const R &r) { return B(expr); }                  \

Reproducible example code

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

class Abstract
{
  bool operator==(const Abstract &other) const
  {
    return true;
  }
  virtual void doit() = 0;
};

class Concrete : public Abstract
{
  virtual void doit()
  {
  }
};

namespace py = pybind11;

PYBIND11_MODULE(mod, m)
{
  py::class_<Abstract>(m, "Abstract")
    .def(py::self == py::self)
    ;
}

compiled with

 c++ -Ipybind11/include -I/usr/include/python3.6 t.cpp

gives

In file included from t.cpp:2:
pybind11/include/pybind11/operators.h: In instantiation of ‘struct pybind11::detail::op_impl<(pybind11::detail::op_id)25, (pybind11::detail::op_type)0, Abstract, Abstract, Abstract>’:
pybind11/include/pybind11/operators.h:59:24:   required from ‘void pybind11::detail::op_<id, ot, L, R>::execute(Class&, const Extra& ...) const [with Class = pybind11::class_<Abstract>; Extra = {}; pybind11::detail::op_id id = (pybind11::detail::op_id)25; pybind11::detail::op_type ot = (pybind11::detail::op_type)0; L = pybind11::detail::self_t; R = pybind11::detail::self_t]’                                                                                                      
pybind11/include/pybind11/pybind11.h:1103:9:   required from ‘pybind11::class_<type_, options>& pybind11::class_<type_, options>::def(const pybind11::detail::op_<id, ot, L, R>&, const Extra& ...) [with pybind11::detail::op_id id = (pybind11::detail::op_id)25; pybind11::detail::op_type ot = (pybind11::detail::op_type)0; L = pybind11::detail::self_t; R = pybind11::detail::self_t; Extra = {}; type_ = Abstract; options = {}]’                                                      
t.cpp:25:30:   required from here
pybind11/include/pybind11/operators.h:130:67: error: ‘bool Abstract::operator==(const Abstract&) const’ is private within this context
 PYBIND11_BINARY_OPERATOR(eq,        eq,           operator==,   l == r)
                                                                 ~~^~~~
pybind11/include/pybind11/operators.h:83:61: note: in definition of macro ‘PYBIND11_BINARY_OPERATOR’
     static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); }   \
                                                             ^~~~
t.cpp:6:8: note: declared private here
   bool operator==(const Abstract &other) const
        ^~~~~~~~
In file included from t.cpp:2:
pybind11/include/pybind11/operators.h:84:14: error: invalid abstract return type ‘Abstract’
     static B execute_cast(const L &l, const R &r) { return B(expr); }                  \
              ^~~~~~~~~~~~
pybind11/include/pybind11/operators.h:130:1: note: in expansion of macro ‘PYBIND11_BINARY_OPERATOR’
 PYBIND11_BINARY_OPERATOR(eq,        eq,           operator==,   l == r)
 ^~~~~~~~~~~~~~~~~~~~~~~~
t.cpp:4:7: note:   because the following virtual functions are pure within ‘Abstract’:
 class Abstract
       ^~~~~~~~
t.cpp:10:16: note:      ‘virtual void Abstract::doit()’
   virtual void doit() = 0;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions