简化在 Pybind11 中为 C++ 模板生成包装器 classes class:模板声明不能出现在块范围内
Simplify generating wrapper classes in Pybind11 for a C++ template class: a template declaration cannot appear at block scope
我正在尝试简化在 Pybind11 中为 C++ 模板 class 生成包装器 classes。这是一个显示问题的最小示例(遵循 答案):
#include <pybind11/pybind11.h>
#include <iostream>
namespace py = pybind11;
template<class T>
class Foo {
public:
Foo(T bar) : bar_(bar) {}
void print() {
std::cout << "Type id: " << typeid(T).name() << '\n';
}
private:
T bar_;
};
PYBIND11_MODULE(example, m) {
template<typename T>
void declare_foo(py::module &m, std::string &typestr) {
using Class = Foo<T>;
std::string pyclass_name = std::string("Foo") + typestr;
py::class_<Class>(m, pyclass_name.c_str())
.def(py::init< T >())
.def("print", &Class::print);
}
declare_foo<int>(m, "Int");
declare_foo<double>(m, "Double");
# More similar declarations follow here...
}
当我编译它时:
g++ -O3 -Wall -shared -std=c++17 -fPIC `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix`
我收到错误:
example.cpp: In function ‘void pybind11_init_example(pybind11::module&)’:
example.cpp:18:5: error: a template declaration cannot appear at block scope
18 | template<typename T>
| ^~~~~~~~
我想出了以下使用宏的解决方法
template<class T>
class Foo {
public:
Foo(T bar) : bar_(bar) {}
void print() {
std::cout << "Type id: " << typeid(T).name() << '\n';
}
private:
T bar_;
};
#define DECLARE_FOO(T, NAME) { \
py::class_<Foo<T> >(m, (std::string("Foo")+NAME).c_str()) \
.def(py::init< T >()) \
.def("print", &Foo<T>::print); \
}
PYBIND11_MODULE(example, m) {
DECLARE_FOO(int, "int");
DECLARE_FOO(float, "float");
}
它似乎可以工作,但是我不确定这个宏是否足够强大。
就像错误提示的那样,您不能在块范围内进行模板声明(您显然在一个 https://en.cppreference.com/w/cpp/language/scope 中)。只需将它移到外面并通过 const 引用(或值)捕获字符串参数。
将代码更改为
template<typename T>
void declare_foo(py::module &m, const std::string &typestr) {
using Class = Foo<T>;
std::string pyclass_name = std::string("Foo") + typestr;
py::class_<Class>(m, pyclass_name.c_str())
.def(py::init< T >())
.def("print", &Class::print);
}
PYBIND11_MODULE(example, m) {
declare_foo<int>(m, "Int");
declare_foo<double>(m, "Double");
}
有效。
作为旁注,您还应该
#include <string>
不建议依赖传递包含。
我正在尝试简化在 Pybind11 中为 C++ 模板 class 生成包装器 classes。这是一个显示问题的最小示例(遵循
#include <pybind11/pybind11.h>
#include <iostream>
namespace py = pybind11;
template<class T>
class Foo {
public:
Foo(T bar) : bar_(bar) {}
void print() {
std::cout << "Type id: " << typeid(T).name() << '\n';
}
private:
T bar_;
};
PYBIND11_MODULE(example, m) {
template<typename T>
void declare_foo(py::module &m, std::string &typestr) {
using Class = Foo<T>;
std::string pyclass_name = std::string("Foo") + typestr;
py::class_<Class>(m, pyclass_name.c_str())
.def(py::init< T >())
.def("print", &Class::print);
}
declare_foo<int>(m, "Int");
declare_foo<double>(m, "Double");
# More similar declarations follow here...
}
当我编译它时:
g++ -O3 -Wall -shared -std=c++17 -fPIC `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix`
我收到错误:
example.cpp: In function ‘void pybind11_init_example(pybind11::module&)’:
example.cpp:18:5: error: a template declaration cannot appear at block scope
18 | template<typename T>
| ^~~~~~~~
我想出了以下使用宏的解决方法
template<class T>
class Foo {
public:
Foo(T bar) : bar_(bar) {}
void print() {
std::cout << "Type id: " << typeid(T).name() << '\n';
}
private:
T bar_;
};
#define DECLARE_FOO(T, NAME) { \
py::class_<Foo<T> >(m, (std::string("Foo")+NAME).c_str()) \
.def(py::init< T >()) \
.def("print", &Foo<T>::print); \
}
PYBIND11_MODULE(example, m) {
DECLARE_FOO(int, "int");
DECLARE_FOO(float, "float");
}
它似乎可以工作,但是我不确定这个宏是否足够强大。
就像错误提示的那样,您不能在块范围内进行模板声明(您显然在一个 https://en.cppreference.com/w/cpp/language/scope 中)。只需将它移到外面并通过 const 引用(或值)捕获字符串参数。
将代码更改为
template<typename T>
void declare_foo(py::module &m, const std::string &typestr) {
using Class = Foo<T>;
std::string pyclass_name = std::string("Foo") + typestr;
py::class_<Class>(m, pyclass_name.c_str())
.def(py::init< T >())
.def("print", &Class::print);
}
PYBIND11_MODULE(example, m) {
declare_foo<int>(m, "Int");
declare_foo<double>(m, "Double");
}
有效。
作为旁注,您还应该
#include <string>
不建议依赖传递包含。