我正在创作一个模板化的头文件库。它没有状态,没有全局变量,没有需要编译的.cpp。有没有可能将其作为一个模块导出/使用?如何导出/使用?有什么好处?有什么陷阱?有一些方便的宏,我可能希望用户有。那些呢?我已经找到了一个使用#ifdef ...来满足模块和老式情况的例子,我想我应该避免这种情况。
#ifdef ...
ioekq8ef1#
我已经找到了一个使用#ifdef的例子......来迎合模块和老式的情况。我想我想避免这种情况。一般来说,这不是最好的方法。你可以用import <header_file.hpp>;把头文件作为一个头文件单元导入,但是你会丢失模块的一些重要方面。如果你想让你的模块版本工作得很好,你需要做有限数量的#define。几乎每一个只有头文件的库都有一些声明被认为是库的一部分,但也有一些声明不是,这些声明通常被放在detail命名空间中,或者试图对用户隐藏它们。模块有一个机制来实现这一点:export。或者更重要的是,他们有办法 * 不 * 在你的界面中放置一些东西:不要export它。但是这需要显式地用export关键字标记你的接口...这在非模块构建中不起作用。所以你需要一个宏来判断构建是否是模块构建,这样你就可以有一个#define解析为export或者什么都没有。您可以执行export namespace my_namespace {};来尝试导出所有内容,但这可能会产生令人不快的副作用。你可能还需要显式地inline导出类的某些类成员,因为模块不会像非模块构建那样隐式地inline非模板类的定义成员。幸运的是,添加inline在非模块构建中会很好地工作。编写一个只有头文件的库和一个模块接口文件,这样用户就可以包含他们喜欢的任何东西,这并不太困难。但是这确实需要一些注意,为了最好地利用模块的特性,你应该使用一些宏。主模块接口单元如下所示:
#ifdef
import <header_file.hpp>;
#define
detail
export
export namespace my_namespace {};
inline
module; //Begin global module fragment. <external header includes> export module MyModuleName; //Begin the actual module purview #define MY_MODULE_NAME_EXPORT export; #include "my_header1.hpp" #include "my_header2.hpp"
<external header includes>是非常重要的。你需要#include * 你的库明确包含的每个 * 文件。如果你包含了C++标准库的一部分,那么就在这里包含它们。这样做的目的是为了阻止这些头文件将头文件的内容推到模块的权限中,您希望包含的库是被推到模块中的 * 唯一代码 *,因此您将这些头文件包含在全局模块片段中,并使用它们的include-guard来防止以后的包含。是的,这意味着你必须为这些头文件保留两个独立的列表,你可以编写一个工具来浏览所有的头文件,并为你建立一个列表,但无论如何,它仍然是你需要拥有的东西。在库头的顶部,在任何include guards之后,您需要这样做:
<external header includes>
#include
#ifndef MY_MODULE_NAME_EXPORT #define MY_MODULE_NAME_EXPORT #endif
这允许您使用MY_MODULE_NAME_EXPORT修饰要导出的任何内容:
MY_MODULE_NAME_EXPORT
MY_MODULE_NAME_EXPORT void some_function() { ... }
如果你是在一个模块构建中,那么它将导出函数;如果你不是,那么它不会。
1条答案
按热度按时间ioekq8ef1#
我已经找到了一个使用
#ifdef
的例子......来迎合模块和老式的情况。我想我想避免这种情况。一般来说,这不是最好的方法。你可以用
import <header_file.hpp>;
把头文件作为一个头文件单元导入,但是你会丢失模块的一些重要方面。如果你想让你的模块版本工作得很好,你需要做有限数量的#define
。几乎每一个只有头文件的库都有一些声明被认为是库的一部分,但也有一些声明不是,这些声明通常被放在
detail
命名空间中,或者试图对用户隐藏它们。模块有一个机制来实现这一点:
export
。或者更重要的是,他们有办法 * 不 * 在你的界面中放置一些东西:不要export
它。但是这需要显式地用export
关键字标记你的接口...这在非模块构建中不起作用。所以你需要一个宏来判断构建是否是模块构建,这样你就可以有一个#define
解析为export
或者什么都没有。您可以执行
export namespace my_namespace {};
来尝试导出所有内容,但这可能会产生令人不快的副作用。你可能还需要显式地
inline
导出类的某些类成员,因为模块不会像非模块构建那样隐式地inline
非模板类的定义成员。幸运的是,添加inline
在非模块构建中会很好地工作。编写一个只有头文件的库和一个模块接口文件,这样用户就可以包含他们喜欢的任何东西,这并不太困难。但是这确实需要一些注意,为了最好地利用模块的特性,你应该使用一些宏。
主模块接口单元如下所示:
<external header includes>
是非常重要的。你需要#include
* 你的库明确包含的每个 * 文件。如果你包含了C++标准库的一部分,那么就在这里包含它们。这样做的目的是为了阻止这些头文件将头文件的内容推到模块的权限中,您希望包含的库是被推到模块中的 * 唯一代码 *,因此您将这些头文件包含在全局模块片段中,并使用它们的include-guard来防止以后的包含。
是的,这意味着你必须为这些头文件保留两个独立的列表,你可以编写一个工具来浏览所有的头文件,并为你建立一个列表,但无论如何,它仍然是你需要拥有的东西。
在库头的顶部,在任何include guards之后,您需要这样做:
这允许您使用
MY_MODULE_NAME_EXPORT
修饰要导出的任何内容:如果你是在一个模块构建中,那么它将导出函数;如果你不是,那么它不会。