- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我已经创建了几个目前仅 header 的 C++ 库。我的类的接口(interface)和实现都写在同一个 .hpp
文件中。
我最近开始觉得这种设计不太好:
我真的很喜欢纯头文件库的各个方面:所有函数都可能被内联,并且它们非常容易包含在您的项目中 - 无需编译/链接任何东西,只需一个简单的 #include
指令。
是否可以两全其美?我的意思是 - 允许用户选择他/她想如何使用图书馆。它还可以加快开发速度,因为我会在“动态链接模式”下处理库以避免荒谬的编译时间,并以“仅头文件模式”发布我的成品以最大限度地提高性能。
第一个逻辑步骤是在 .hpp
和 .inl
文件中划分接口(interface)和实现。
不过,我不确定如何前进。我已经看到许多库将 LIBRARY_API
宏添加到它们的函数/类声明中 - 也许需要类似的东西来允许用户选择?
我所有的库函数都以 inline
关键字为前缀,以避免 “multiple definition of...” 错误。我假设关键字将被 .inl
文件中的 LIBRARY_INLINE
宏替换?对于“仅标题模式”,该宏将解析为 inline
,而对于“动态链接模式”,该宏将解析为无。
最佳答案
初步说明:我假设是 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
你的实现文件看起来和往常一样:
// foo.cpp
#include "foo.hpp"
#include <iostream>
void foo()
{
std::cout << "foo";
}
如果定义了 INLINE_LIBRARY
,则函数被声明为内联,实现就像 .inl 文件一样包含在内。
如果定义了 STATIC_LIBRARY
,则函数声明时不带任何说明符,用户必须将 .cpp 文件包含到他/她的构建过程中。
如果定义了IMPORT_LIBRARY
,则导入函数,不需要任何实现。
如果定义了EXPORT_LIBRARY
,函数会被导出,用户必须编译那些.cpp文件。
在静态/导入/导出之间切换是很常见的事情,但我不确定将仅 header 添加到等式中是否是一件好事。通常,有充分的理由来定义内联或不这样做。
就我个人而言,我喜欢将所有内容都放入 .cpp 文件中,除非它确实必须被内联(如模板)或者它在性能方面有意义(非常小的函数,通常是单行)。这减少了编译时间和 - 更重要的 - 依赖关系。
但如果我选择内联定义某些内容,我总是将其放在单独的 .inl 文件中,只是为了保持头文件干净且易于理解。
关于c++ - 库设计: allow user to decide between "header-only" and dynamically linked?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25606736/
Akka 新手。创建一个扩展 SupervisorStrategy 的新 Scala 类为我提供了以下模板: class MySupervisorStrategy extends Supervisor
Selenium Webdriver如何确定按钮是启用还是禁用?我用过isEnabled() 两个按钮的方法-一个启用,另一个禁用,但在两种情况下均返回true。除了使用isEnabled()之外,还
我试图让闭包编译器内联一些以简单模式封装在配置对象中的代码,而无需任何类型注释。 React does this并设法降低 bundle 大小 我观察到以下情况: a.js (function mai
我一直在尝试针对 Android 进行改造。响应为空。如果我的理解是正确的,这可能是因为 400 响应或我的模型类中的响应建模不正确。我得到的响应如下: {"itemA":"data", "itemB
我正在尝试使用 Accord 库实现的 k 最近邻。首先,我使用了 double[][] inputs = new double[15000][]; int[] out
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题吗? 通过 editing this post 添加细节并澄清问题. 关闭 8 年前。 Improve t
当我们使用 sadd 在集合中插入一个成员时,是否有一种确定的方式来插入数据?例如, 127.0.0.1:6380> smembers test 1) "hello world" 2) "hello"
我已经看过一些YOLO教程,但是我发现很难确定要分割图像的每个单元格的“ anchor ”框是否是预先确定的。在我经历的其中一个指南中,该图像被分为 13x13 单元格,并指出每个单元格预测 5 an
有没有办法在 Coq 中对相互递归类型使用决定相等策略? 例如,如果我有这样的东西: Inductive LTree : Set := | LNil | LNode (x: LTree) (y
我有几个类,例如 MyClassA MyClassB MyClassC 和 MyClassD 我想要一个给定 Class 类型的函数,该函数将创建(并执行任何操作......)一个作为该类实例的对象。
如何从以下 mysql 查询的 where 子句中引用 'decider'? SELECT *, CASE WHEN (cond1) THEN 1 W
我正在使用 C++ 中的 QuickFix 为代理 FIX 平台实现启动器端。他们的 FIX 规范提供了他们支持的消息列表;登录、心跳和其他消息。 MessageCracker(修复 4.2)为同一类
我正在尝试使用 Accord.NET 库进行对象分类,但我未能找到任何合适的示例,并且文档不足以理解该过程。我当前的代码是 Predictor = new Boost(); AdaBoost Algo
今天我在 msdn 中看到博客,我注意到如何计算算法的时间复杂度。我完全理解如何计算算法的时间复杂度,但最后作者提到了以下几行 Adding everything up I get (N+4)+(5N
随着我们的办公室升级到 Window 7,我的任务是更新登录脚本以与 Windows 7 一起使用。所述脚本的创建者早已不复存在,我不是批处理文件专家。 我要做的是确定操作系统。当我执行一些网络管理职
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
当我尝试在 Mac 上的 Andriod Studio 上运行该项目时,出现如下内部错误: Andriod Emulator closed because of an internal error:
我正在阅读一篇关于 Haskell 以及 HList 是如何实现的研究论文,并想知道所描述的技术何时可以确定,何时不能确定类型检查器。此外,因为您可以使用 GADT 做类似的事情,所以我想知道 GAD
我最近在一个用GCC 8编译的软件中研究了段错误。代码如下所示(这只是一个草图) struct Point { int64_t x, y; }; struct Edge { // some o
大多数句子分割器都能够在正确的位置分割文本流。 我正在寻找一个模型来决定某些文本是否是句子。 最佳答案 简单的解决方案:使用解析器(例如,Stanford Parser,它是免费的并且是Java的,但
我是一名优秀的程序员,十分优秀!