Skip to content

Commit f6a45e2

Browse files
author
mikeblome
committed
ready for proofread
1 parent e57c5cc commit f6a45e2

File tree

1 file changed

+50
-47
lines changed

1 file changed

+50
-47
lines changed

docs/cpp/modules-cpp.md

Lines changed: 50 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@ ms.description: Modules in C++20 provide a modern alternative to header files.
77

88
# Overview of modules in C++
99

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.
1111

1212
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.
1313

14-
and require the **/experimental:modules** compiler option as well as **/std:c++latest**.
15-
1614
## Enable modules in the Microsoft C++ compiler
1715

1816
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
2119

2220
## Consume the C++ Standard Library as modules
2321

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:
2523

2624
- std.regex provides the content of header \<regex>
2725
- std.filesystem provides the content of header \<experimental/filesystem>
2826
- std.memory provides the content of header \<memory>
2927
- std.threading provides the contents of headers \<atomic>, \<condition_variable>, \<future>, \<mutex>, \<shared_mutex>, and \<thread>
3028
- std.core provides everything else in the C++ Standard Library
3129

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:
3331

3432
```cpp
3533
import std.core;
@@ -38,47 +36,61 @@ import std.regex;
3836

3937
## Basic example
4038

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`.
4240

4341
```cpp
4442
export module Foo;
4543

46-
namespace Bar
44+
#define ANSWER 42
45+
46+
namespace Bar
4747
{
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();
5154
}
5255
}
5356
```
5457

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.
5659

5760
```cpp
61+
5862
import Foo;
63+
import std.core;
5964

60-
using namespace Bar;
65+
using namespace std;
6166

6267
int main()
6368
{
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
6572
}
6673

6774
```
6875

69-
The import declaration can appear only at the global scope.
76+
The import declaration can appear only at global scope.
7077

7178
## Implementing modules
7279

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.)
7483

7584
## Modules and namespaces
7685

7786
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.
7887

7988
### Module partitions
8089

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:
8294

8395
```cpp
8496
module Foo:part1
@@ -87,7 +99,7 @@ module Foo:part1
8799
and the partition interface file begins like this:
88100

89101
```cpp
90-
module Foo:part1
102+
export module Foo:part1
91103
```
92104

93105
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
106118
```
107119

108120
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-
113121

114122
## Modules and header files
115123

116-
You can include header files in a module source file by putting the #include before 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.
117125

126+
```cpp
127+
// MyModuleA.cpp
118128

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"
120131

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
130136
```
131137

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:
133139

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+
```
135147

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
137149

138-
### Legacy imports
150+
>[NOTE!]
151+
> This section is informational only. Legacy imports are not yet implemented in the Microsoft C++ compiler.
139152
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.)
141154

142155
```cpp
143156
import <vector>
144157
import "myheader.h"
145158
```
146159

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)
156-
157160
## See Also

0 commit comments

Comments
 (0)