带有 "auto" 关键字的 pybind11 用于重载函数

pybind11 with "auto" keyword for overloaded function

我想帮助包装使用 "auto" 的 return 类型的重载函数。 例如,第 699 行和第 708 行的函数位于 https://github.com/microsoft/SEAL/blob/master/native/src/seal/ciphertext.h

        SEAL_NODISCARD inline auto &scale() noexcept
        {
            return scale_;
        }
        SEAL_NODISCARD inline auto &scale() const noexcept
        {
            return scale_;
        }

当我尝试如下绑定时,

py::class_<Ciphertext>(m, "Ciphertext")  
     .def("scale", (auto  (Ciphertext::*)() const)&Ciphertext::scale, "returns a constant reference to the scale")   

我看到这个错误

...mseal.cpp:223:18: error: invalid use of ‘auto’
   .def("scale", (auto (Ciphertext::*)() const)&Ciphertext::scale, "returns a constant reference to the scale")

我正在使用 C++17 和 python3。我不想修改 C++ SEAL 库。 谢谢。

编辑:我刚刚发现 pybind11 有一个辅助构造来做同样的事情,导致很多 simpler/cleaner 代码。将原始答案中的 PYBIND11_MODULE 块替换为:

PYBIND11_MODULE(mseal, m) {
    py::class_<Ciphertext>(m, "Ciphertext")
        .def(py::init<>())
        .def("scale",
             py::overload_cast<>(&Ciphertext::scale, py::const_),
             "returns a constant reference to the scale")
        .def("scale_nonconst",
             py::overload_cast<>(&Ciphertext::scale),
             "returns a reference to the scale");
}

原始答案:您需要 decltype 才能获得 return 类型,需要 std::declval 才能消除 decltype 的重载歧义。下面是一个完整的工作示例(最低 C++14),我在其中添加了非常量版本只是为了表明您可以完全控制以下任一选择:

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

#include <iostream>
#include <utility>

namespace py = pybind11;

class Ciphertext {
public:
    inline auto &scale() noexcept {
        std::cerr << "non-const called" << std::endl;
        return scale_;
    }
    inline auto &scale() const noexcept {
         std::cerr << "const called" << std::endl;
       return scale_;
    }

private:
    int scale_;
};


PYBIND11_MODULE(mseal, m) {
    py::class_<Ciphertext>(m, "Ciphertext")
        .def(py::init<>())
        .def("scale",
             static_cast<decltype(std::declval<Ciphertext const&>().scale()) (Ciphertext::*)() const>(&Ciphertext::scale),
             "returns a constant reference to the scale")
        .def("scale_nonconst",
             static_cast<decltype(std::declval<Ciphertext&>().scale()) (Ciphertext::*)()>(&Ciphertext::scale),
             "returns a reference to the scale");
}

其中,编译成 mseal.so 时按预期工作:

>>> import mseal
>>> mseal.Ciphertext().scale()
const called
0
>>> mseal.Ciphertext().scale_nonconst()
non-const called
0
>>>