Content outdated
For up-to-date documentation see Overview of modules in C++.This preview only supports C++ modules in the IDE for MSBuild projects. While the MSVC toolset is supported by any build system, Visual Studio’s IDE support for CMake doesn’t support C++ modules yet. We will let you know once it is! As always, please try it out and let us know if you have any feedback.
Module Basics
C++ modules allow you to closely control what is made available to the translation units that consume them. Unlike headers, they won’t leak macro definitions or private implementation details (no ridiculous prefixes needed). Also, unlike headers, they are built once and then can be consumed many times across your projects, reducing build overhead.
C++20 introduces new keywords to define and consume modules and Visual Studio uses a new file type “.ixx” to define a module’s interface. Read on for the details.
Getting Started with Modules in Visual Studio
If you created a brand-new project in the latest preview, you don’t need to do anything. However, before you can add or consume modules in existing projects you need to make sure you are using the latest C++ Language Standard.
To do this, set the C++ Language Standard to “Preview /std:c++latest”. If you have multiple projects in your solution, remember to do this for all of them.
And that’s it! You are ready to use C++ modules with Visual Studio.
Creating Modules
To add a module to a project you will need to create a module interface. These are normal C++ source files with the extension “.ixx”. They can include headers, import other modules, and will include the exported definitions of your module. You can add as many of these to a project as you want.
Here’s how this then looks in the Solution Explorer. In this example, the fib
and printer
projects both define C++ modules.
Note: While this example shows all module interfaces in “.ixx” files, any C++ source file can be treated as a module interface. To do this, set the “Compile As” property on a source file to “Compile As Module”. The “Compile As” property can be found on the “Advanced” tab on any source file’s properties page.
Exporting Modules
So, what actually goes into a module interface? The example below defines a simple module called DefaultPrinter
and exports a single struct:
module; //begins global module fragment #include <iostream> export module DefaultPrinter; export struct DefaultPrinter { void print_element(int e) { std::cout << e << " "; } void print_separator() { std::cout << ", "; } void print_eol() { std::cout << '\n'; } };
To break the example down a bit, you can see the new export syntax on lines 1, 5, and 7. Line 1 specifies that this is a module interface. Line 5 defines and exports the module itself and line 7 exports a struct. Each module can export many items, such structs, classes, functions, and templates.
Module interfaces can include headers and import other modules. When they are imported, they will not leak any details from these included headers or modules unless you explicitly import them. This isolation can help avoid naming collisions and leaking implementation details. You can safely define macros and use namespaces in module interfaces too. They will not leak like traditional headers.
To #include
headers in a module interface, ensure you put them in the global module fragment between module;
and export module mymodule;
.
This example puts the implementation in the module’s interface, but that is optional. If you look back at the solution explorer before you can see the fibgen.ixx interface has a corresponding implementation in fibgen.cpp.
Its interface looks like this:
export module FibGenerator; export fib gen_fib(int start, int &len);
With a corresponding implementation:
module FibGenerator; fib gen_fib(int start, int &len) { //... }
Here, the interface defines the module name and exports gen_fib
. The corresponding implementation uses the module
keyword to define which module the implementation belongs to so everything can be combined into a cohesive unit automatically at build time.
Consuming Modules
To consume modules, use the new import
keyword.
module; #include <ranges> #include <concepts> import DefaultPrinter; struct DefaultFormatter { template<is_series S, is_printer T> void format(T t, S s) { while (!s.done()) { t.print_element(s.next()); t.print_separator(); } t.print_eol(); } };
All exported items from the module interface will be available for use. This example makes use of the DefaultPrinter
module in the first example, importing it on line 5.
Your code can consume modules in the same project or any referenced ones automatically (using project-to-project references to static library projects).
Consuming Modules from Other Modules
You can also import modules from another module interface. Here is an example that expands on the DefaultPrinter
module above:
module; #include <iostream> import DefaultPrinter; export module TabbedPrinter; export struct TabbedPrinter : DefaultPrinter { void print_separator() { std::cout << "\t"; } };
This example imports the DefaultPrinter
module above and overrides its print_separator
function. Other code can now import this TabbedPrinter
without needing to worry about the details of DefaultPrinter
. Visual Studio will make sure everything is built in the right order.
External Modules
It is also possible to reference modules that exist on disk, instead of ones belonging to another project in the solution. Care needs to be taken here, however, because modules are compiled, binary files. You must make sure they are compatible with the way you are building your projects.
You can tell Visual Studio to look for modules on disk by editing the Additional Module Dependencies property:
IntelliSense and Modules
All the IntelliSense features you know and love also work with modules. Features like code completion, parameter help, Find All References, Go To Definition and Declaration, rename, and more all work across solutions the way you would expect when you use modules.
Here you can see Find All References and Peek Definition working with our TabbedPrinter
module above. For instance, it can show all references of the DefaultPrinter
structure exported from the DefaultPrinter
module and display its definition:
You can also Go To or Peek the Definition of a module itself from anywhere that imports it:
See Modules in Action
To see all of this in action, check out our modules demo from CppCon 2020. There are many other demos of the latest Visual Studio and C++20 features in action too if you are interested.
Header Units
A header unit is a standard C++ incantation to invoke the generation of metadata (IFC files) – for well-behaved header files, in particular standard library headers – similar to those generated for modules with the goal of speeding up overall build time, if done judiciously. However, unlike Modules, header units do not really provide isolation the way Modules do: macro definitions and other preprocessor states are still leaked to the consumers of the header units. You use a header unit via the import "header.h";
or import <header>;
syntax. In Visual Studio, the metadata for header units are automatically generated by the build system. All items declared and reasonable definitions in the header file (and its includes) are made available to the consumer, as would an #include
file. Like in the case of module consumption, macro definitions and other preprocessor states active in the code that imports a header unit will not influence the imported header unit in any way. However, unlike a module, any macro definition will be available for use in your code when you import a header unit. Header units are primarily a transition mechanism, not substitute for modules. If you have a chance to consider a named module vs. a header unit, we encourage you to invest the effort in designing proper modules. We will cover header units in depth in future blogs, especially their use in migrating existing codebases to uses of modules.
Full IDE and toolset support for header units is coming soon. You can track the status of header unit support for the Microsoft STL here on GitHub.
Feedback
If you are interested in trying out C++ modules with your own code, I urge you to grab the latest Visual Studio Preview. Please try it out and let use know if you have any questions or feedback. If you find any issues or have a suggestion, the best way to reach out to us is to Report a Problem.
Awesome! great article! It helps me a lot Please visit my site pinoy
Hey, thanks for the module tour! You mentioned that you can share modules between projects by referencing a static library project with the desired modules. Will it be possible to reference executable projects the same way to access its modules? We’re currently in the process of modularizing a bigger project of ours and this would greatly simplify our project structure.
It was hard for me to follow at first. But, I took hours to do it and it was awesome! I told my friends in continuous flow portable oxygen concentrator
- There is no clear description of the problems that the addition of modules should solve.
- There is no test to demonstrate that the stated goal has been achieved.
- The main problem with build time in C ++ is related to the need to include implementations of template classes in the header file, while there is not a word about template classes in the article.
- There are no recommendations under what conditions...
Hi!
Will PCH support including a module? This issue is blocking me from moving slowly my code to modules without breaking the compilation.
Awesome! great article! It helps me a lot from commercial door repair tampa
What about offering the required information about module dependencies to third-party tools like CMake. CMake is no module support at all and they complain that no compiler (GCC, Clang, MVSC) provides the required information? Are you in contact with them?
Relevant CMake issue #18355: https://gitlab.kitware.com/cmake/cmake/-/issues/18355
How can I write modules in `.cpp` files? One of the important goals of C++ modules was to remove the need for headers. But `.ixx` introduces another file extension!
> Unlike headers, they won’t leak macro definitions or private implementation details (no ridiculous prefixes needed).
Indeed this is one of the most important aspect of modules for me, that no private implementation details leak out and pollute the namespace of the caller. So I played around with a pimpl class in Preview 16.8.0, but I see that internal details do still seem to leak out sometimes (but not other times), and I wonder if it's...
I’m having the same issue, except in my case the leaking code is in the standard library (“symbol ‘unique_ptr’ has already been defined”), so there is no simple workaround. I see you have reported this back in January (https://developercommunity.visualstudio.com/content/problem/900116/c-modules-name-collision.html), but they still haven’t fixed it. I upvoted the issue, really hope they get around to it soon, as it hinders my ability to use modules at scale!
Andras: I value the upvote. Do you have your own `std::unique_ptr` class which clashes with the official std o_o, or do you mean just importing unique_ptr from <memory> from multiple places? If the latter, that sounds a little different from my case because the std::unique_ptr is really the same class in both cases. I've been #include'ing in the global module fragment (between "module;" and that file's "export module MyModule;" statement) without issue. Eventually we'll...
I’m only using the standard unique_ptr, and I only ever #include anything in the global module fragment. I put my module test project aside for a bit, but will try to dig a little deeper and make a minimal repro case.
You mention that Intellisense should be working with the latest VS Preview and modules, right? I've been using modules in a regular VS solution and it compiles and runs fine, however Intellisense has no idea what the exported types are, everything is highlighted as an error.
I'm fine with waiting for the final version of VS, but if you are implying in this post that the final version is pretty much what's offered now, how...
I experienced a similar issue (VS 16.8.1). In a very minimal test case, I got “module not found” warnings from the IDE. The code did compile and behaved correctly however. Also features like “peek definition” and “find all references” worked correctly. Only the IDE reported the red squiggles. But after a while, the squiggles just disappeared. Aparrenty, “something” rescanned the code.
It sounds like something is wrong. There are some fixes still coming, but exported types should at least be showing up in the member list and other IntelliSense features. Would you mind opening an issue on Developer Community so we can follow up in more detail: https://docs.microsoft.com/en-us/visualstudio/ide/how-to-report-a-problem-with-visual-studio
That is concerning, since it’s very late in the development cycle to not even be aware of this problem.
I opened a ticket at https://developercommunity2.visualstudio.com/t/Intellisense-doesnt-work-at-all-with-C/1242837, fingers crossed!
I experience the same problem with a very minimalistic test case and preview 6. Even the line "import foo;" gives an intellisense error "could not find module file for module foo". The project builds fine tho, with some mysterious "Scanning sources for module dependencies..." that I would very much like to know how it's implemented, because the new cl -sourceDependencies option cannot be used with modules contrary to what another recent blog post said.
I tried...
I have the same problem and reported it here
but they say that the issue could not be reproduced.