首页 > 解决方案 > pybind11 带有“auto”关键字的重载函数

问题描述

我想帮助包装一个使用“auto”返回类型的重载函数。例如,https://github.com/microsoft/SEAL/blob/master/native/src/seal/ciphertext.h中第 699 行和第 708 行的函数

        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 库。谢谢你。

标签: overloadingautopybind11

解决方案


编辑:我刚刚发现 pybind11 有一个辅助构造来做同样的事情,从而导致更简单/更清洁的代码。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获取返回类型并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
>>>

推荐阅读