pybind / pybind/pybind11

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

Open
#1,487 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
18k
Forks
2.3k
Avg merge
5d 17h
Merged PRs (30d)
10

Description

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;

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with pybind11/include/pybind11/operators.h, especially execute_cast and the operator implementation used by .def(py::self == py::self). Compile the provided abstract-class example first, then inspect existing operator tests for comparable coverage. Done means the example no longer requires an invalid abstract return type when wrapping the operator.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.