10、可导入的标准库头文件

        所有的c++头文件,比如<iostream>,<vector>,<string>,等等,都是可导入的头文件,可用导入声明进行导入。这就意味着,可以写出如下的代码:

import <vector>;

        当然了,从c++23开始,简单地导入命名模块std就更方便了,而不是手工导入那些需要的可导入的头文件。例如,下面的代码可使得所有标准库中的可用:

import std;

        你现在已经知道,可导入的c++标准库头文件没有任何.h扩展名,例如<vector>,它们定义了std命名空间或std子命名空间中的所有。

        在C中,标准库头文件名以.h结尾,例如<stdio.h>,不用命名空间。

        大部分C中的标准库功能在c++中可用,通过两种不同的头文件:

  • 推荐没有.h扩展名的而带有c前缀的版本,例如,<cstdio>。这些会把所有的东西放到std命名空间。
  • C风格版本的是带有.h扩展名,例如:<stdio.h>。它们不用命名空间。不建议使用它们,除非书写需要同时在c++与C中都有效的代码。我们以后不再讨论这种场景。

        注意:直到c++23,<name.h>的使用C标准库头文件是过时的,从c++23开始,它们的使用不再过时,但不鼓励。

        从技术上来讲,旧版本也允许把代码放到std命名空间中,新版本也允许把代码放到全局命名空间中。但这种行为没有被标准化,所以不应该依赖这种假设。

        早前提到过,当使用import std;时,就自动可以访问C风格的函数,比如定义在<cmath>中的数学函数。它们会在std命名空间,例如:std::sqrt()。如果import std.compat;这些C风格的函数就会在全局命名空间上可用,例如::sqrt()。

        然而,如果不能使用std或std.compat命名的模块,那么就要记住了C标准库头文件不保证可以使用import声明导入成功。这种情况下,安全起见,要使用#include <cxyz>而不是imprt <cxyz>;。

        还有,在前面章节中提到过,导入合适的模块,比如:std或std.compat,不会使任何定义在模块中的C风格的宏对导入的代码可用。在使用C标准库中的C风格的宏时要记住,这特别重要。不幸中之万幸,它们不是很多!其中一个是<cassert>,一个定义了assert()宏的C标准库头文件,这个我们以后会讨论。既然命名的std与std.compat模块不会使assert()宏对于导入代码可用,既然<cassert>是一个C标准库头文件,因此不保证可导入,必须使用#include <cassert>来访问assert()。

        注意:如果可以导入一个头文件,推荐这样做。只有在不能导入的情况下才会去#include一个头文件,例如,因为头文件的内容依赖于一些预处理#define。

        如果确实需要在模块接口或模块实现文件中#include头文件,#include指令应该放在全局模块部分,一定要在任何命名模块声明之前,以未命名的模块声明开始。全局模块部分只能包含预处理指令,例如#include,#define,等等。这样的全局模块部分与注释是唯一允许出现在命名模块声明之前的。例如,如果需要使用<cassert>C头文件中的功能,可以使用如下代码:

module;    // Start of the global module fragment
#include <cassert> // Include legacy header files

export module person; // Named module declaration
import std;
export class Person { /* ... */ };

        警告:把所有模块接口或模块实现文件中的#include指令放到全局模块部分。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部