You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/cpp/modules-cpp.md
+50-47Lines changed: 50 additions & 47 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,12 +7,10 @@ ms.description: Modules in C++20 provide a modern alternative to header files.
7
7
8
8
# Overview of modules in C++
9
9
10
-
C++20 introduces *modules*, a modern solution for componentization of C++ libraries and programs. A module is a set of source code files that are compiled independently of the program that imports them rather than being textually included by the preprocessor. Modules eliminate or greatly reduce many of the problems associated with the use of header files, and also potentially reduce compilation times. Macros, preprocessor directives, and non-exported names declared in a module are not visible and therefore have no effect on the compilation of the translation unit that imports the module. You can import modules in any order without concern for macro redefinitions. Declarations in the importing translation unit do not participate in overload resolution or name lookup in the imported module. After a module is compiled once, the result can be reused wherever else the module is imported in a project.
10
+
C++20 introduces *modules*, a modern solution for componentization of C++ libraries and programs. A module is a set of source code files that are compiled independently of the translation units that import them. Modules eliminate or greatly reduce many of the problems associated with the use of header files, and also potentially reduce compilation times. Macros, preprocessor directives, and non-exported names declared in a module are not visible and therefore have no effect on the compilation of the translation unit that imports the module. You can import modules in any order without concern for macro redefinitions. Declarations in the importing translation unit do not participate in overload resolution or name lookup in the imported module. After a module is compiled once, the results are stored in a binary file that describes all the exported types. That file can be processed much faster than a header file, and can be reused by the compiler every place where the module is imported in a project.
11
11
12
12
Modules can be used side by side with header files. A C++ source file can import modules and also #include header files. In some cases, a header file can be imported as a module rather than textually #included by the preprocessor. We recommend that new projects use modules rather than header files as much as possible. For larger existing projects under active development, we suggest that you experiment with converting legacy headers to modules to see whether you get a meaningful reduction in compilation times.
13
13
14
-
and require the **/experimental:modules** compiler option as well as **/std:c++latest**.
15
-
16
14
## Enable modules in the Microsoft C++ compiler
17
15
18
16
As of Visual Studio 2019 version 16.2, modules are not fully implemented in the Microsoft C++ compiler. You can use the modules feature to create single-partition modules and to import the Standard Library modules provided by Microsoft. To enable support for modules, compile with `/experimental:modules` and `std:c++latest`. In a Visual Studio project, right-click the project node in **Solution Explorer** and choose **Properties**. Set the **Configuration** drop-down to **All Configurations**, then choose **Configuration Properties** > **C/C++** > **Language** > **Enable C++ Modules (experimental)**.
@@ -21,15 +19,15 @@ Modules must be compiled with the [/Ehsc](../build/reference/eh-exception-handli
21
19
22
20
## Consume the C++ Standard Library as modules
23
21
24
-
By importing the Standard Library as modules rather than #including it through header files, you can potentially speed up compilation times depending on the size of your project. The library is componentized into the following modules:
22
+
By importing the C++ Standard Library as modules rather than #including it through header files, you can potentially speed up compilation times depending on the size of your project. The library is componentized into the following modules:
25
23
26
24
- std.regex provides the content of header \<regex>
27
25
- std.filesystem provides the content of header \<experimental/filesystem>
28
26
- std.memory provides the content of header \<memory>
29
27
- std.threading provides the contents of headers \<atomic>, \<condition_variable>, \<future>, \<mutex>, \<shared_mutex>, and \<thread>
30
28
- std.core provides everything else in the C++ Standard Library
31
29
32
-
To consume these modules, just add an import statement to the top of the source code file:
30
+
To consume these modules, just add an import statement to the top of the source code file. For example:
33
31
34
32
```cpp
35
33
import std.core;
@@ -38,47 +36,61 @@ import std.regex;
38
36
39
37
## Basic example
40
38
41
-
The following example shows a simple module definition in a source file called **Foo.ixx**. The **ixx** extension is required for module interface files in Visual Studio. In this example, the interface file contains the function definition as well as the declaration but the definitions can be placed in a separate file (as shown in a later example). The **export module Foo** statement indicates that this file is the primary interface for a module called **Foo**. The **export** modifier on f() indicates that this function will be visible when **Foo** is imported by another program or module. Note that the module references a namespace `Bar`.
39
+
The following example shows a simple module definition in a source file called **Foo.ixx**. The **.ixx** extension is required for module interface files in Visual Studio. In this example, the interface file contains the function definition as well as the declaration. However, the definitions can be also placed in one or more separate files (as shown in a later example). The **export module Foo** statement indicates that this file is the primary interface for a module called `Foo`. The **export** modifier on `f()` indicates that this function will be visible when `Foo` is imported by another program or module. Note that the module references a namespace `Bar`.
42
40
43
41
```cpp
44
42
exportmodule Foo;
45
43
46
-
namespaceBar
44
+
#defineANSWER 42
45
+
46
+
namespaceBar
47
47
{
48
-
export int f()
49
-
{
50
-
return 108;
48
+
int f_internal() {
49
+
return ANSWER;
50
+
}
51
+
52
+
export int f() {
53
+
return f_internal();
51
54
}
52
55
}
53
56
```
54
57
55
-
The file **MyProgram.cpp** uses the **import** statement to access the names exported by **Foo**.
58
+
The file **MyProgram.cpp** uses the **import** statement to access the name that is exported by `Foo`. Note that the name `Bar` is exported, but not all of its members.
56
59
57
60
```cpp
61
+
58
62
import Foo;
63
+
import std.core;
59
64
60
-
usingnamespaceBar;
65
+
usingnamespacestd;
61
66
62
67
intmain()
63
68
{
64
-
int answer = f();
69
+
cout << "The result of f() is " << Bar::f() << endl; // 42
70
+
// int i = Bar::f_internal(); // C2039
71
+
// int j = ANSWER; //C2065
65
72
}
66
73
67
74
```
68
75
69
-
The import declaration can appear only at the global scope.
76
+
The import declaration can appear only at global scope.
70
77
71
78
## Implementing modules
72
79
73
-
You can create a module with a single interface file (.ixx) that exports names and includes implementations of all functions. You can also put the implementations in one or more separate implementation files (.cxx), similar to how .h and .cpp files are used. An interface file and the set of implementation files that back it are called a *module unit*. An implementation file cannot contain the export keyword. For larger modules, you can split the module into multiple module units called *partitions*. Each partition consists of an interface file backed by one or more implementation files. The primary interface file imports the partition interfaces, and implicitly exports them. Declarations in any of the partitions are visible within the entire module. No special precautions are need to avoid one-definition-rule (ODR) errors in cases where multiple partitions import the same partition. You can declare a name (function, class, etc.) in one partition and define it in another.
80
+
You can create a module with a single interface file (.ixx) that exports names and includes implementations of all functions and types. You can also put the implementations in one or more separate implementation files, similar to how .h and .cpp files are used. The **export** keyword is used in the interface file only. An implementation file can **import** another module, but cannot **export** any names. Implementation files may be named with any extension. An interface file and the set of implementation files that back it are treated as a special kind of translation unit called a *module unit*. A name that is declared in any implementation file is automatically visible in all other files within the same module unit.
81
+
82
+
For larger modules, you can split the module into multiple module units called *partitions*. Each partition consists of an interface file backed by one or more implementation files. (Note: As of Visual Studio 2019 version 16.2, partitions are not yet fully implemented.)
74
83
75
84
## Modules and namespaces
76
85
77
86
The rules for namespaces in modules are the same as in any other code. If a declaration within a namespace is exported, the enclosing namespace (excluding non-exported members) is also implicitly exported. If a namespace is explicitly exported, all declarations within that namespace definition are exported.
78
87
79
88
### Module partitions
80
89
81
-
A module partition is similar to a module, except that is shares ownership of all declarations in the entire module. A partition's name must begin with the module name followed by a colon. A partition implementation file begins like this:
90
+
>[!NOTE]
91
+
> This section is provided for completeness. Partitions are not yet implemented in the Microsoft C++ compiler.
92
+
93
+
A module can be componentized into *partitions*, each consisting of an interface file and zero or more implementation files. A module partition is similar to a module, except that it shares ownership of all declarations in the entire module. All names that are exported by partition interface files are imported and re-exported by the primary interface file. A partition's name must begin with the module name followed by a colon. Declarations in any of the partitions are visible within the entire module. No special precautions are need to avoid one-definition-rule (ODR) errors. You can declare a name (function, class, etc.) in one partition and define it in another. A partition implementation file begins like this:
82
94
83
95
```cpp
84
96
module Foo:part1
@@ -87,7 +99,7 @@ module Foo:part1
87
99
and the partition interface file begins like this:
88
100
89
101
```cpp
90
-
module Foo:part1
102
+
exportmodule Foo:part1
91
103
```
92
104
93
105
To access declarations in another partition, a partition must import it, but it can only use the part name, not the module name:
@@ -106,52 +118,43 @@ export import :part2
106
118
```
107
119
108
120
The primary interface unit can import partition implementation files, but cannot export them because those files are not allowed to export any names. This enables a module to keep implementation details internal to the module.
109
-
110
-
Declarations in a you can import an implementation in a partition but not re-xport it.
111
-
112
-
113
121
114
122
## Modules and header files
115
123
116
-
You can include header files in a module source file by putting the #includebefore the module declaration. These files are considered to be in the global module fragment, and no module "owns" them. module can only see symbols there that are in headers it specifically includes. The global module only contains symbols that are actually used.
124
+
You can include header files in a module source file by putting the `#include` directive before the module declaration. These files are considered to be in the *global module fragment*. A module can only see the names in the *global module fragment*that are in headers it explicitly includes. The global module fragment only contains symbols that are actually used.
117
125
126
+
```cpp
127
+
// MyModuleA.cpp
118
128
119
-
A module cannot export a macro. A macro in an importing module cannot affect the imported module. Components that need to export macros should continue to use header files, with module-based subcomponents for the parts that are well behaved. For example, an existing library that provides interfaces controlled by a preprocessor macro symbol UNICODE can modularize its constituents and continue to provide a traditional header file-based solution as follows:
129
+
#include"customlib.h"
130
+
#include"anotherlib.h"
120
131
121
-
```cpp
122
-
// Header file C.h
123
-
#ifndef C_INCLUDED
124
-
#define C_INCLUDED
125
-
#ifdef UNICODE
126
-
import C.Unicode;
127
-
#else
128
-
import C.Ansi;
129
-
#endif// C INCLUDED
132
+
import std.core;
133
+
import MyModuleB;
134
+
135
+
//... rest of file
130
136
```
131
137
132
-
Only exported names are visible outside the module; unlike a header file, a module owns the non-exported names that it declares. Non-exported names cannot be source of "One Definition Rule (ODR)" violations when a module is imported into a program or another module. A compiler error is raised if a program imports two modules that export identical names with the same type(s) in the same namespace.
138
+
You can use a traditional header file to control which modules are imported:
133
139
134
-
The use of modules does not affect class member name lookup rules. A class that is declared (but not defined) in a module interface is seen as an incomplete type by any importing module, even if the module itself defines it in a non-exported name or function.
140
+
```cpp
141
+
// MyProgram.h
142
+
import std.Ccore
143
+
#ifdef DEBUG_LOGGING
144
+
import std.filesystem;
145
+
#endif
146
+
```
135
147
136
-
Modules are included in your program as source files, but unlike headers which must be parsed in every translation unit in which they appear, a module only needs to be compiled once. The compiler creates a binary interface file that describes all the exported types. That file can be processed much faster than a header file, and the binary interface file can be reused by the compiler every place where the module is imported. In larger projects, the reduction in compilation times can be significant.
148
+
### Imported header files
137
149
138
-
### Legacy imports
150
+
>[NOTE!]
151
+
> This section is informational only. Legacy imports are not yet implemented in the Microsoft C++ compiler.
139
152
140
-
Some headers are sufficiently self-contained that they are allowed to be brought in using the import keyword. An imported header is called a *legacy import*. Any #defines in the header itself are visible in the importing program.
153
+
Some headers are sufficiently self-contained that they are allowed to be brought in using the **import** keyword. The main difference between an imported header and an imported module is that any preprocessor definitions in the header are visible in the importing program immediately after the import statement. (Preprocessor definitions in any files included by that header are *not* visible.)
141
154
142
155
```cpp
143
156
import <vector>
144
157
import"myheader.h"
145
158
```
146
159
147
-
everything is exported including all #defines inside that file, but not any defines brought in from other included headers. A module can import any number of other modules. Modules are orthogonal to namespaces. For example, multiple modules are used to expose the STL using the std namespace.
148
-
149
-
### Preamble
150
-
151
-
Import statements and #include statements only. No declarations. The #defines are immediately available even for other imported headers in the preamble.
152
-
153
-
### Argument dependent lookup when instantiating templates declared in a module
154
-
155
-
Path of instantiation for templates declared in imported headers (30:03)
0 commit comments