Vit*_*meo 29 c++ library-design libraries header-only c++11
我创建了几个目前只有标头的 C++库.我的类的接口和实现都写在同一个.hpp
文件中.
我最近开始认为这种设计不是很好:
我真的很喜欢只有头文件库的方面:所有函数都可以内联,并且它们非常容易包含在你的项目中 - 不需要编译/链接任何东西,只需要一个简单的#include
指令.
是否有可能充分利用两个世界?我的意思是 - 允许用户选择他/她想要如何使用库.它还可以加快开发速度,因为我以"动态链接模式"处理库以避免荒谬的编译时间,并以"仅标题模式"发布我的成品以最大化性能.
第一个逻辑步骤是将接口和实现划分为.hpp
和.inl
文件.
不过,我不确定如何前进.我已经看到很多库将LIBRARY_API
宏添加到它们的函数/类声明中 - 可能需要类似的东西来允许用户选择?
我的所有库函数都以inline
关键字为前缀,以避免"多个定义......"错误.我假设关键字将被文件中的LIBRARY_INLINE
宏替换.inl
?宏将解析inline
为"仅标题模式",而不是"动态链接模式".
Hor*_*ing 15
初步说明:我假设是Windows环境,但这应该可以轻松转移到其他环境.
您的图书馆必须为四种情况做好准备:
因此,让四个预处理器定义了这些情况:INLINE_LIBRARY
,STATIC_LIBRARY
,IMPORT_LIBRARY
,和EXPORT_LIBRARY
(这只是一个例子,你可能想使用一些复杂的命名方案).用户必须根据他/她想要的内容定义其中一个.
然后你可以这样写你的标题:
// foo.hpp
#if defined(INLINE_LIBRARY)
#define LIBRARY_API inline
#elif defined(STATIC_LIBRARY)
#define LIBRARY_API
#elif defined(EXPORT_LIBRARY)
#define LIBRARY_API __declspec(dllexport)
#elif defined(IMPORT_LIBRARY)
#define LIBRARY_API __declspec(dllimport)
#endif
LIBRARY_API void foo();
#ifdef INLINE_LIBRARY
#include "foo.cpp"
#endif
Run Code Online (Sandbox Code Playgroud)
您的实现文件看起来像往常一样:
// foo.cpp
#include "foo.hpp"
#include <iostream>
void foo()
{
std::cout << "foo";
}
Run Code Online (Sandbox Code Playgroud)
如果INLINE_LIBRARY
已定义,则函数将内联声明,并且实现将像.inl文件一样包含在内.
如果STATIC_LIBRARY
已定义,则声明函数时不使用任何说明符,并且用户必须将.cpp文件包含在他/她的构建过程中.
如果IMPORT_LIBRARY
已定义,则导入函数,并且不需要任何实现.
如果EXPORT_LIBRARY
已定义,则导出函数,用户必须编译这些.cpp文件.
在静态/导入/导出之间切换是一个非常常见的事情,但我不确定是否在方程式中添加标题是一件好事.通常,有充分的理由来定义内联或不内联.
就个人而言,我喜欢把一切都变成.cpp文件,除非它真的有内联(如模板),或者是有意义的性能代价(非常小的功能,通常是单行).这减少了编译时间和 - 更重要的 - 依赖性.
但是,如果我选择内联定义内容,我总是把它放在单独的.inl文件中,只是为了保持头文件清晰易懂.