pybind11 с ключевым словом "auto" для перегруженной функции - PullRequest
0 голосов
/ 11 декабря 2019

Мне нужна помощь в переносе перегруженной функции, которая использует возвращаемый тип «auto». Например, функции в строках 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. Спасибо.

1 Ответ

0 голосов
/ 12 декабря 2019

РЕДАКТИРОВАТЬ : Я только что обнаружил, что 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
>>>
...