消除非常量和常量访问方法的歧义Pybind11

问题描述

我正在尝试使用 Pybind11 包装一些 C++ 类。 类 (Alpha) 有两个 getter,一个返回对成员 force_ 的常量引用,另一个返回非常量引用。

struct Dummy {
  double x{3.3};
};

class Alpha {

 const Dummy& force() const {return force_;}
 Dummy& force() {return force_;}
 
 private:
   Dummy force_;
};

我最初尝试使用 py::return_value_policy 但是这样,似乎我没有正确地消除两个版本的函数 force()间的歧义,因为我得到 note: template argument deduction/substitution Failed:Couldn’t deduce template parameter ‘Func’

py::class_<Alpha>(m,"Alpha")
      .def(py::init())
      .def("force",&Alpha::force,"returns reference",py::return_value_policy::reference_internal)
      .def("force","returns copy",py::return_value_policy::copy);
}

我是否正朝着完全错误的方向前进?我真的不想改变代码的 C++ 端。一个附带问题是:我怎么能明确地写出 &Alpha::force 来表示常量或非常量版本。

解决方法

我不知道 pybind,但我想 Funcdef 试图从它的第二个参数推断的类型。问题是您无法获得指向重载集的函数指针。您只能获得指向单个函数的函数指针。

文档说明 Func 可以是普通的 C++ 函数、函数指针或 lambda 函数

好的,但它不能是一整套重载!

这就是为什么对于您的课程(我必须公开 force!),这不会出于同样的原因:

int main() {
    auto x = &Alpha::force;
}

产生的错误是:

<source>:15:10: error: variable 'x' with type 'auto' has incompatible initializer of type '<overloaded function type>'
    auto x = &Alpha::force;
         ^   ~~~~~~~~~~~~~

无法仅从 &Alpha::force 推断类型。


您可以通过 static_cast 从重载集中选择一个:

auto x = static_cast< const Dummy& (Alpha::*)() const>(&Alpha::force);

非常量类似:

auto y = static_cast< Dummy& (Alpha::*)()>(&Alpha::force);

PS:您在文档中的引用实际上没有提到成员函数。我想那是由于报价不完整。如果 def 不能接受成员函数指针,您必须将 force 设为静态,或者将调用包装在自由函数 / lambda 中。不要忘记,指向成员函数的指针与指向自由函数的指针有着根本的不同(它们需要一个对象才能被调用)。