C++头文件包装库
C++ header file wrapper library
我正在尝试模仿我最近看到的项目模式,以提供"C++二进制兼容"的API。 我通过向纯 C 接口提供一个C++头文件包装器来做到这一点。 (这与 C++ OpenCL 包装文件 cl.hpp 使用纯 C OpenCL 接口所做的技巧相同。
下面是一个精简的示例。
foo.h
是纯 C 接口:
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++包装器:
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.h
、foo.hpp
和foo.dll
(带有导出库)。 Foo.dll 本可以使用 MSVC2012、MSVC2013 或 mingw 进行编译,但 Joe User 仍然可以使用 MSVC2015。 这一切都解决了,因为非二进制可移植C++包装器实现位于公共标头中。
问题是:我的包装器有点复杂,我想简化它通过向下移动一些较大方法的定义。 即我希望C++接口简洁并与实现分开列出(可以在下面)。
// 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
对于瘦包装器,将成员函数保持inline
是有意义的。这可以通过在类中定义它们来完成(如在已发布代码的第一个片段中),或者在类外部定义它们并显式声明它们inline
例如在您的示例中:
// 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,而不会导致多个定义编译器错误。引用内联说明符的文档:
编译器是否实际内联函数只要每个定义出现在不同的翻译单元中,程序中的内联函数就可以有多个定义。例如,可以在多个源文件中 #include 的头文件中定义内联函数。
(在每次出现时"扩展"内联代码与生成实际函数调用的意义上)对于声明为 inline
的函数的标准所保证的行为无关紧要,并且不会影响/更改。从同一链接页面:
由于关键字 inline 的这种含义是非绑定的,因此编译器可以自由地对任何未标记为内联的函数使用内联替换,并且可以自由生成对标记为内联的任何函数的函数调用。这些选择不会更改上面列出的有关多个定义和共享静态数据的规则。
- AcquireCredentialsHandleA() 返回 PFX 文件的0x8009030e(安全包中没有可用的凭据
- 禁止显示有关包含文件中 #pragma 包的警告
- 选择特定版本的 Visual Studio 命令行工具包,并根据特定版本的C++运行时环境编译文件
- 如何解开参数包包装器?
- 如何使用 AWS C++ 开发工具包在给定的开始和结束日期范围内列出 S3 中的文件
- 在实现文件中,我们应该更喜欢"using namespace"指令还是将实现包装在命名空间 { } 中?
- C 包装器C++库周围没有不必要的头文件
- 如何链接我自己的 .so 文件而不是操作系统捆绑包 .so 文件?
- 使用开发工具包将文件上传到 AWS C++
- Swig C++ python 包装器文件解释
- 将仅标头库的包含包装在单个 cpp 文件中
- 在C 中解开包装数据包
- 使用带有 MEX 包装器的帮助程序 C 文件从 MATLAB 2016 调用C++代码时出现问题
- TCP-Server以数据包结构(非Java客户端)发送文件
- 致命错误 C1083:无法打开包含文件:'atlbase.h' Pyinsane 包
- 可视化 将 TCP 服务器数据包保存到 C++ 中的文件
- Buildroot 包需要一个带有C++大文件错误的工具链
- 获取包含C++的捆绑包中文件的路径(CFBundleGetMainBundle)
- 短包装/拆包到内部
- 如何在visual studio 2010 C++中制作带有所需.dll和lib(opencv)文件的.exe文件包