为什么 Boost Python 试图实例化一个抽象类型?

Why is Boost Python trying to instantiate an abstract type?

我有以下 C++ class:

#include <cmath>
#include <stdexcept>
#include <string>

struct AbstractShape
{
  virtual ~AbstractShape() { }
  virtual double area() const noexcept = 0;
};

class Square : public AbstractShape
{
  const double side_;

public:
  double area() const noexcept override {
    return side_ * side_;
  }

  Square(double side) : side_(side) { }
};

和以下 Boost python 绑定: #include "Shape.h"

#include <boost/python.hpp>

BOOST_PYTHON_MODULE(Shape)
{
  using namespace boost::python;

  struct AbstractShapeWrap : AbstractShape, wrapper<AbstractShape>
  {
    double area() {
      if(override area = this->get_override("area"))
        return area();
      return AbstractShape::area(); 
    }

    double default_area() {
      return AbstractShape::area();
    }
  };

  class_<AbstractShape>("AbstractShape", no_init)
    .add_property("area", &AbstractShape::area, &AbstractShapeWrap::default_area)
  ;

  class_<Square, bases<AbstractShape> >("Square", init<double>())
  ;
}

当我编译时:

clang++ -std=c++14 Shape.py.cpp -c $(python3-config --includes)

我得到:

In file included from Shape.py.cpp:3:
In file included from /usr/local/include/boost/python.hpp:18:
In file included from /usr/local/include/boost/python/class.hpp:23:
In file included from /usr/local/include/boost/python/object/class_metadata.hpp:14:
/usr/local/include/boost/python/object/value_holder.hpp:62:11: error: field type 'AbstractShape' is an abstract class
    Value m_held;
          ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/type_traits:1568:40: note: in instantiation of template class
      'boost::python::objects::value_holder<AbstractShape>' requested here
    : public integral_constant<size_t, __alignof__(_Tp)> {};
                                       ^
/usr/local/include/boost/python/object/instance.hpp:29:32: note: in instantiation of template class 'std::__1::alignment_of<boost::python::objects::value_holder<AbstractShape> >'
      requested here
        boost::python::detail::alignment_of<Data>::value
                               ^
/usr/local/include/boost/python/object/instance.hpp:45:30: note: in instantiation of template class
      'boost::python::objects::instance<boost::python::objects::value_holder<AbstractShape> >' requested here
        std::size_t, value = sizeof(instance_data)
                             ^
/usr/local/include/boost/python/object/make_instance.hpp:36:28: note: in instantiation of template class
      'boost::python::objects::additional_instance_size<boost::python::objects::value_holder<AbstractShape> >' requested here
            type, objects::additional_instance_size<Holder>::value);
                           ^
/usr/local/include/boost/python/object/class_wrapper.hpp:29:30: note: in instantiation of function template specialization 'boost::python::objects::make_instance_impl<AbstractShape,
      boost::python::objects::value_holder<AbstractShape>, boost::python::objects::make_instance<AbstractShape, boost::python::objects::value_holder<AbstractShape> >
      >::execute<const boost::reference_wrapper<const AbstractShape> >' requested here
        return MakeInstance::execute(boost::ref(x));
                             ^
/usr/local/include/boost/python/converter/as_to_python_function.hpp:27:72: note: (skipping 4 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
        convert_function_must_take_value_or_const_reference(&ToPython::convert, 1L);
                                                                       ^
/usr/local/include/boost/python/object/class_metadata.hpp:218:25: note: in instantiation of function template specialization 'boost::python::objects::class_metadata<AbstractShape,
      boost::python::detail::not_specified, boost::python::detail::not_specified, boost::python::detail::not_specified>::register_aux2<AbstractShape, boost::integral_constant<bool,
      false> >' requested here
        class_metadata::register_aux2((T*)0, use_callback());
                        ^
/usr/local/include/boost/python/object/class_metadata.hpp:204:25: note: in instantiation of member function 'boost::python::objects::class_metadata<AbstractShape,
      boost::python::detail::not_specified, boost::python::detail::not_specified, boost::python::detail::not_specified>::register_aux' requested here
        class_metadata::register_aux((T*)0);
                        ^
/usr/local/include/boost/python/class.hpp:460:19: note: in instantiation of member function 'boost::python::objects::class_metadata<AbstractShape,
      boost::python::detail::not_specified, boost::python::detail::not_specified, boost::python::detail::not_specified>::register_' requested here
        metadata::register_(); // set up runtime metadata/conversions
                  ^
/usr/local/include/boost/python/class.hpp:591:11: note: in instantiation of member function 'boost::python::class_<AbstractShape, boost::python::detail::not_specified,
      boost::python::detail::not_specified, boost::python::detail::not_specified>::initialize' requested here
    this->initialize(no_init);
          ^
Shape.py.cpp:22:7: note: in instantiation of member function 'boost::python::class_<AbstractShape, boost::python::detail::not_specified, boost::python::detail::not_specified,
      boost::python::detail::not_specified>::class_' requested here
      class_<AbstractShape>("AbstractShape", no_init)
      ^
./Shape.h:8:22: note: unimplemented pure virtual method 'area' in 'AbstractShape'
      virtual double area() const noexcept = 0;
                     ^
1 error generated.

为什么 boost::python 试图实例化抽象 class?

我的绑定或调用需要更改什么?

缺少 boost::noncopyable 可能是根本原因,即

class_<AbstractShape, boost::noncopyable>("AbstractShape", no_init)

另外像 AbstractShape::area() 这样的东西可能不应该工作,因为它是一个纯虚拟方法。

Shape.h

struct AbstractShape
{
    virtual ~AbstractShape() { }
    virtual double area() const noexcept = 0;
};

class Square : public AbstractShape
{
    const double side_;

public:
    double area() const noexcept override {
        return side_ * side_;
    }

    Square(double side) : side_(side) { }
};

Shape.py.cpp

#include <boost/python.hpp>
#include "Shape.h"

BOOST_PYTHON_MODULE(Shape)
{
    using namespace boost::python;

    struct AbstractShapeWrap : AbstractShape, wrapper<AbstractShape> {
        double area() {
            return this->get_override("area")();
        }

        double default_area() {
            return this->get_override("area")();
        }
    };

    class_<AbstractShape, boost::noncopyable>("AbstractShape", no_init)
        .add_property("area", &AbstractShape::area,
                      &AbstractShapeWrap::default_area);

    class_<Square, bases<AbstractShape> >("Square", init<double>());
}