C++ 头文件包装器库

标签 c++ c dll

我正在尝试模仿我最近看到的项目模式来提供“C++ 二进制兼容”API。我通过为纯 C 接口(interface)提供 C++ 头文件包装器来实现这一点。 (这与 C++ OpenCL 包装器文件 cl.hpp 对纯 C OpenCL 接口(interface)所做的相同。)

这是一个精简的例子。

foo.h 是纯 C 接口(interface):

typdef void *foo_t;
extern "C" DLLEXPORT foo_t foo_open(const char *);
extern "C" DLLEXPORT int foo_compute(foo_t, const char *buf, int blen);
extern "C" DLLEXPORT void foo_close(foo_t);

foo.hpp 是 C++ 包装器,它也与 header 一起分发:

struct Foo {
  foo_t handle;
  Foo() { handle = foo_open(...); }
  ~Foo() { foo_close(handle); }
  std::string compute() {
    char buf[512];
    foo_compute(handle, buf, sizeof(buf))
    return std::string(buf);
  }
}

Joe 用户获取 foo.hfoo.hppfoo.dll(带有导出库)。 Foo.dll 可以使用 MSVC2012、MSVC2013 或 mingw 编译,但 Joe User 仍然可以使用 MSVC2015。由于非二进制可移植 C++ 包装器实现位于公共(public) header 中,因此一切顺利。

问题是:我的包装器有点复杂,我想简化它 通过将一些较大方法的定义向下移动。 IE。我希望 C++ 接口(interface)简洁并与实现分开列出(可以在下面)。

// INTERFACE: keep it concise
struct Foo {
  foo_t handle;
  Foo() { handle = foo_open(...) }
  ~Foo() { foo_close(handle); }
  std::string compute(); // keep it concise
}

// IMPLEMENTATIONS: most folks don't need to read this
std::string Foo::compute() {
   char buf[512];
   foo_compute(handle, buf, sizeof(buf))
   return std::string(buf);
}

问题是,如果多个目标文件包含 foo.hpp(它们会),我最终会得到多个 Foo::compute 的定义,因为每个目标文件戳出一个拷贝,而不是使用内联类定义的版本。

cl.hpp 我只是在内联所有定义之后对其建模,所以这没有帮助。我环顾了互联网,但找不到我正在尝试做的事情的一个很好的例子,但也许我使用了错误的命名法。

如果这些只是函数,我只是将它们标记为 static 并且它们不会逃脱它们的编译单元。最坏的情况是,我想我可以使用静态辅助函数来解决这个问题。

有什么想法吗?

谢谢!

引用资料: [1] 这有点相关。 https://chadaustin.me/cppinterface.html

最佳答案

对于 包装器,保持成员函数内联 是有意义的。这可以通过在类定义它们(如发布代码的第一段)在类外定义它们并显式声明它们来完成 内联 例如在你的例子中:

// IMPLEMENTATIONS: most folks don't need to read this
inline std::string Foo::compute() {
    char buf[512];
    foo_compute(handle, buf, sizeof(buf));
    return std::string(buf);
}

声明为 inline 的函数可以在头文件中定义,该头文件在多个源文件(又名 翻译单元)中被#include,而不会导致 多个定义 编译器错误。引用 inline specifier 的文档:

There may be more than one definition of an inline function in the program as long as each definition appears in a different translation unit. For example, an inline function may be defined in a header file that is #include'd in multiple source files.

编译器是否实际内联函数(在每次出现时“扩展”内联代码与生成实际函数调用的意义上)对于由声明为 inline 的函数的标准。来自相同的链接页面:

Since this meaning of the keyword inline is non-binding, compilers are free to use inline substitution for any function that's not marked inline, and are free to generate function calls to any function marked inline. Those choices do not change the rules regarding multiple definitions and shared statics listed above.

关于C++ 头文件包装器库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35494081/

相关文章:

c - 在运行时定义数组大小

c++ - 在 NetBeans 动态库项目中使用不同目录中的源文件

java - 将数字从 Base B1 转换为 Base B2 而不使用任何中间基数

c++ - 使用lambda表达式创建线程时,如何为每个线程提供自己的lambda表达式拷贝?

c - 从 GtkEntry 获取属性为 "text"的文本

C - 基本 I/O 读取只读 "\n"

c++ - 将数据从 Delphi DLL 传递到 C++ 应用程序

c - 如何构建一个类型以传递给一个 DLL 函数,该函数采用指向内部数组的结构的指针?

c++ - 用于在 C++ 中同步线程的二进制信号量

c++这个问题的问题在哪里? (带参数的构造函数)