我可以将C++模板类导出到C,再导入到Python吗?
对于一个非模板类,我会写类似这样的代码
但是如果我的类是一个模板类,我就不知道该怎么做了。
我尝试过类似的做法,但并没有成功。
extern "C" {
Demodulator<double>* Foo_new_double(){ return new Demodulator<double>(); }
Demodulator<float>* Foo_new_float(){ return new Demodulator<float>(); }
void demodulateDoubleMatrix(Demodulator<double>* demodulator, double * input, int rows, int columns){ demodulator->demodulateMatrixPy(input, rows, columns) }
}
2 个回答
C++语言最开始是C语言的一个扩展,也就是说,它包含了C语言没有的新关键词、语法和功能。C语言没有类的概念,也没有成员函数的概念,更不支持访问限制的概念。此外,C语言也不支持继承。不过,C++和C最大的不同在于模板。C语言只有宏定义,没有其他的。
所以,直接把C++代码暴露给C语言是不行的,你必须在C++中使用C风格的代码来展示C++的部分。
template<T> T foo(T i) { /* ... */ }
extern "C" int fooInt(int i) { return foo(i); }
不过,C++最初基本上是一个C代码生成器,C++仍然可以与C的ABI(应用程序二进制接口)进行单向交互:成员函数实际上是通过将this->function(int arg);
转换成ThisClass0int1(this, arg);
这样的形式来实现的。理论上,你可以写一些东西来处理你的代码,可能会用到clang。
但这并不是一件简单的事情,SWIG、Boost::Python和Cython已经很好地解决了这个问题。
不过,模板的问题在于,编译器在你“实例化”(使用)它们之前是不会处理它们的。std::vector<>
并不是一个具体的东西,直到你指定std::vector<int>
或其他的东西。现在,唯一的具体实现就是std::vector<int>
。在你某个地方指定之前,std::vector<string>
在你的二进制文件中是不存在的。
你可能想先看看这个 http://kos.gd/2013/01/5-ways-to-use-python-with-native-code/,选择一个工具,比如SWIG,然后开始构建一个接口,把你想要的东西暴露给C。这比自己手动构建包装器要简单得多。根据你使用的工具,可能只需要写一行代码,比如using std::vector<int>
或typedef std::vector<int> IntVector
之类的。
---- 编辑 ----
模板类的问题在于,你创建了一个C语言无法理解的完整类型,想想看:
template<typename T>
class Foo {
T a;
int b;
T c;
public:
Foo(T a_) : a(a_) {}
void DoThing();
T GetA() { return a; }
int GetB() { return b; }
T GetC() { return c; }
};
C语言不支持class
这个关键词,更不用说理解成员a、b和c是私有的,或者什么是构造函数,C语言也不理解成员函数。
同样,C语言也不理解模板,所以你需要手动生成一个实例化,就像C++自动做的那样:
struct FooDouble {
double a;
int b;
double c;
};
不过,所有这些变量都是私有的。那么你真的想把它们暴露出去吗?如果不想,你可能只需要把"FooDouble"定义为与Foo大小相同的类型,并做一个宏来实现。
然后你需要为成员函数写替代品。C语言不理解构造函数,所以你需要写一个
extern "C" FooDouble* FooDouble_construct(double a);
FooDouble* FooDouble_construct(double a) {
Foo* foo = new Foo(a);
return reinterept_cast<FooDouble*>(foo);
}
和一个析构函数
extern "C" void FooDouble_destruct(FooDouble* foo);
void FooDouble_destruct(FooDouble* foo) {
delete reinterpret_cast<Foo*>(foo);
}
以及类似的访问器。
注意:你的问题和代码有点矛盾,所以我暂时不考虑代码部分。
C++中的模板其实是一种复杂的宏机制,它是在编译时解决的。换句话说,最终生成的程序只包含了模板实例化后的代码(也就是当你给模板传入参数,通常是类型时,得到的代码),这些代码才是你可以从程序中导出到其他语言的。导出这些代码就像导出任何普通类型一样,比如std::string
。
因为模板本身在编译后就不存在了,所以你无法从程序中导出它们,无论是导出到C语言、Python,还是C++!不过对于C++来说,你可以提供模板本身,但这并不意味着它们会包含在最终的程序中。
有两个假设:
- 导出/导入是通过程序的二进制文件进行的。当然,你可以写一个解析C++的导入工具。
- C++曾经规定过(或者说现在规定?)导出模板,但据我所知,这个功能在实际使用中并没有真正实现,所以我就不提这个选项了。