Pybind - Любопытно повторяющийся шаблон

У меня следующая структура класса (упрощенный пример моей реальной реализации):

/* TestClass.hpp */
#pragma once

template <class Impl>
class CurRecTemplate {
protected:
    CurRecTemplate() {}
    ~CurRecTemplate() {}

    Impl& impl() { return static_cast<Impl&>(*this); }
    const Impl& impl() const { return static_cast<const Impl&>(*this); }
};

template <class Impl>
class BaseClass : public CurRecTemplate<Impl> {
public:
    BaseClass() { };

    template <class FuncType>
    double eval(const FuncType& func, double x) const
    {
        return this->impl().evalImplementation(func, x);
    }
};

class DerivedClass : public BaseClass<DerivedClass> {
public:
    template <class FuncType>
    double evalImplementation(const FuncType& f, double x) const
    {
        return f(x);
    };
};

а потом

/* Source.cpp */
#include <pybind11/pybind11.h>
#include "TestClass.hpp"

namespace py = pybind11;

template<typename Impl>
void declare(py::module &m, const std::string& className) {
    using DeclareClass = BaseClass<Impl>;

    py::class_<DeclareClass, std::shared_ptr<DeclareClass>>(m, className.c_str())
        .def(py::init<>())
        .def("eval", &DeclareClass::eval);
}

PYBIND11_MODULE(PyBindTester, m) {
    declare<DerivedClass>(m, "DerivedClass");
}

который я в значительной степени основал на ответе на этот вопрос Класс шаблонов многих типов PyBind11 . Однако я получаю следующие ошибки:

C2783 'pybind11 :: class_> & pybind11 :: class _> :: def (const char *, Func &&, const Extra & ...)': не удалось вывести аргумент шаблона для 'Func' ... \ source.cpp 10 < br> C2672 'pybind11 :: class _> :: def': совпадающая перегруженная функция не найдена ... \ source.cpp 12

Похоже, это связано со вторым template <class FuncType>, который я нигде не могу определить, поскольку общая функция func будет передана позже. Есть ли способ обойти эту проблему?


person Phil-ZXX    schedule 27.06.2018    source источник


Ответы (1)


eval должен быть функцией, которая принимает значение типа double и возвращает значение типа double (или типы, конвертируемые в тип double), поэтому вы можете специализировать шаблон с помощью &DeclareClass::eval<double(*)(double)>; или лучше включить <functional> и <pybind11/functional.h>, и вы можете полностью удалить шаблон и заставить eval принять std::function<double(double)> в качестве своего первого параметра.

Чтобы быть более конкретным, я бы переписал следующим образом

/* TestClass.hpp */
#pragma once
#include <functional>

template <class Impl>
class CurRecTemplate {
protected:
    CurRecTemplate() {}
    ~CurRecTemplate() {}

    Impl& impl() { return static_cast<Impl&>(*this); }
    const Impl& impl() const { return static_cast<const Impl&>(*this); }
};

template <class Impl>
class BaseClass : public CurRecTemplate<Impl> {
public:
    BaseClass() { };

    double eval(std::function<double(double)> func, double x) const
    {
        return this->impl().evalImplementation(func, x);
    }
};

class DerivedClass : public BaseClass<DerivedClass> {
public:
    double evalImplementation(std::function<double(double)> f, double x) const
    {
        return f(x);
    };
}; 

/* Source.cpp */
#include <pybind11/pybind11.h>
#include "TestClass.hpp"
#include <pybind11/functional.h>

namespace py = pybind11;

template<typename Impl>
void declare(py::module &m, const std::string& className) {
    using DeclareClass = BaseClass<Impl>;

    py::class_<DeclareClass, std::shared_ptr<DeclareClass>>(m, className.c_str())
        .def(py::init<>())
        .def("eval", &DeclareClass::eval);
}

PYBIND11_MODULE(Project1, m) {
    declare<DerivedClass>(m, "DerivedClass");
}
person Dominic Price    schedule 27.06.2018
comment
в чем причина использования std::shared_ptr<DeclareClass>? - person user10634362; 16.02.2021