Haskell FFI:如何与简单的C++进行接口交互?

7
到目前为止,从我所读到的资料来看,使用FFI与C++结合非常困难。其中最大的原因之一似乎是将C++对象转换为Haskell对象。我的问题是,我没有C语言的经验,但有几年的C++经验,并且我更喜欢面向对象编程。因此,我自然希望从C++中受益。
那么,我可以编写设计用于Haskell FFI的C++程序来解决这些问题吗?C++可以在底层执行任何操作,但API应该类似于C,即不交换对象,没有重载的顶层函数等等。有什么需要注意的缺陷吗?
(为了让您能够更好地理解我的项目,请考虑使用SciPy的Weave来加速Python代码。)

如果你想使用C ++,那就使用C ++,而不是Haskell。否则,保留FFI用于与本地库进行接口交互和极其性能关键的代码。 - Cat Plus Plus
1
@CatPlusPlus 对于性能至关重要的代码,我会选择使用C++。 - David
除非在最后一招时使用 FFI。 - Cat Plus Plus
2
是的。现在我们可以专注于我的问题吗? - David
1
答案是“是的,如果你小心,你可以使用extern“C”函数”,这与Haskell没有真正关系。 - Cat Plus Plus
显示剩余2条评论
1个回答

14

是的,您可以通过FFI使用C++代码,只要在该C++代码上方公开C API即可。

一种常见的模式是将类的所有"方法"简单地包装为C程序,以便将该类的对象视为不透明指针,这些函数可以应用于该指针。

例如,给定代码(foo.h):

class foo
{
public:
  foo(int a) : _a(a) {}
  ~foo() { _a = 0; } // Not really necessary, just an example

  int get_a() { return _a; }
  void set_a(int a) { _a = a; }

private:
  int _a;
}

您可以轻松地创建所有这些方法的 C 版本 (foo_c.h)。

#ifdef __cplusplus
typedef foo *foo_ptr;
extern "C"
{
#else
typedef void *foo_ptr;
#endif

foo_ptr foo_ctor(int a);
void foo_dtor(foo_ptr self);

int foo_get_a(foo_ptr self);
void foo_set_a(foo_ptr self, int a);
#ifdef __cplusplus
} /* extern "C" */
#endif

那么,必须有一些适配器代码通过C++接口实现C接口 (foo_c.cpp):

#include "foo.h"
#include "foo_c.h"

foo_ptr foo_ctor(int a) { return new foo(a); }
void foo_dtor(foo_ptr self) { delete self; }

int foo_get_a(foo_ptr self) { return self->get_a(); }
void foo_set_a(foo_ptr self, int a) { self->set_a(a); }

现在可以在Haskell FFI定义中包含头文件foo_c.h


为什么C语言中要使用void *?typedef struct foo* foo_ptr;在两种情况下都可以工作。 - Öö Tiib
因为foo是一个类而不是结构体,如果你有一个支持C++的C编译器并且可以这样做,那么它就是极其不标准的。 - dflemstr
你的代码中显然有 #ifdef __cplusplus,因此你显然使用两个编译器进行编译,并且 typedef struct foo* foo_ptr; 在两个编译器中都编译成了指向 foo 的指针。你不能在 C 中定义 foo,因此你不能在 C 中对指向 foo 的指针进行解引用(或进行指针算术运算),但是你也无法使用 void* 进行这些操作。 - Öö Tiib
我们在讨论创建一个Haskell FFI,而不是制作理想的C API,包括const正确性和类型有效性等等。这真的无关紧要。 - dflemstr
你听起来好像认为 Haskell 是一个能吃掉任何东西的垃圾。就我所知,Haskell 开发人员非常保守,肯定会在他们的代码中将两个不同的不透明 C 结构分开。 - Öö Tiib
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接