How to use modules in C++

Hi all,

I'm going to use modules (instead of including headers) in C++ but don't know how it is prevalent and popular or how many of you use it.
Do you suggest that, please? If so what tutorial should I use for my first use of that?
Windows 10 x64, Visual Studio 2022
Last edited on
Visual Studio 2019/2022 is the only compiler that currently can use modules AFAIK, so popularity and prevalence in older pre-C++20 code is rather moot.

The EASIEST way to use modules instead of headers is change #include to import and add a ; (semicolon) to the end.

1
2
3
4
5
6
import <iostream>;

int main()
{
   std::cout << "Hello, C++20 modules!\n";
}


Forget the MS perversion of import std.core;, it is non-standard, using it requires mucking around with changing a lot of project setting to get this module usage to work. And still VS will vomit warnings.

As long as your project is set to use C++20 as the C++ language standard using modules should work without too much of a hitch.
My .cpp project uses C++20 language standard but for the code above I get two errors:
'cout': is not a member of 'std'
'cout': undeclared identifier
Last edited on
Using custom interface modules isn't much different than using pre-C++20 headers. Here's some code.

math.hpp:
1
2
3
4
5
6
7
8
9
#pragma once

auto square(const auto& x) { return x * x; }  // An abbreviated function template

const double lambda = 1.303577269034296391257;        // Conway's constant

enum class Oddity     { Even, Odd };
bool isOdd(int x)     { return x % 2 != 0; }
auto getOddity(int x) { return isOdd(x) ? Oddity::Odd : Oddity::Even; }

main.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <format>

#include "math.hpp"

int main()
{
   std::cout << "Lambda squared: " << square(lambda) << std::endl;

   int number;
   std::cout << "\nPlease enter an odd number: ";
   std::cin >> number;
   std::cout << std::endl;

   switch (getOddity(number))
   {
      using enum Oddity;

   case Odd:
      std::cout << "Well done! And remember: you have to be odd to be number one!";
      break;

   case Even:
      std::cout << std::format("Odd, {} seems to be even?", number);
      break;
   }
   std::cout << '\n';
}
Lambda squared: 1.69931

Please enter an odd number: 5

Well done! And remember: you have to be odd to be number one!

M'ok, changing a header to an import interface module isn't that hard. Best way to do it is using the "Add New Item" wizard in VS. You should see a Module item available, with the default name of "Module.ixx." Change the name to "math.cppm" and use this code:
1
2
3
4
5
6
7
8
9
10
11
export module math;

export auto square(const auto& x) { return x * x; }  // An abbreviated function template

export const double lambda = 1.303577269034296391257;        // Conway's constant

export enum class Oddity { Even, Odd };

bool isOdd(int x) { return x % 2 != 0; }  // Module-local function (not exported)

export auto getOddity(int x) { return isOdd(x) ? Oddity::Odd : Oddity::Even; }

Now, your main.cpp? Change the 3 #includes to:
1
2
3
4
import <iostream>;
import <format>;

import math;

You shouldn't need to change anything in main. Compile, and run. That's it for simple module support.
frek wrote:
I get two errors

M'ok, what VS version are you using? It should be Version 17.2.3.

Now, there are TWO places where the C++ language standard can be set. Check both.
Main Menu->Project->Properties. This will bring up the project's Property Pages dialog.

1. Configuration Properties->General->C++ Language Standard: ISO C++20 Standard (/std:c++20)

2. Configuration Properties->C++->Language->C++ Language Standard: ISO C++20 Standard (/std:c++20)
OK, this is my example.
Vector.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
module;
export module Vector;

export class Vector {
public:
	Vector(int s);
	double& operator[](int i);
	int size();
private:
	double* elem; // elem points to an array of sz doubles
	int sz;
};

Vector::Vector(int s)
	:elem{ new double[s] }, sz{ s } // initialize members
{ }

double& Vector::operator[](int i)
{
	return elem[i];
}

int Vector::size()
{
	return sz;
}

export int size(const Vector& v) { return v.size(); } 


main.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
import Vector; 
import <iostream>;

int main()
{
	std::cout << "Hello, C++20 modules!\n";
	Vector vec(1);
	vec[0] = 5;
	std::cout << vec[0] << '\n';

	return 0;
}


Get many errors! :(
https://imgur.com/IfGLmSI
NO! Use the EXACT code I gave you earlier. Including the names of the files. Get THAT to work then we can talk about your example.

The annoying thing is the default language standard for VS is C++14 (it shows as blank). That means you have to set the language standard to C++20 EVERY TIME you start a new project.

OR....

Change the default. It isn't that hard.

The following thread is about adding a custom library to the VS New Project defaults, changing the Language Standard is the same procedure.

http://www.cplusplus.com/forum/lounge/271176/ (frikkin' forum software URL interpreter!)

FYI, I can see EXACTLY why you are getting the errors.
Last edited on
As I said earlier, "{u}sing custom interface modules isn't much different than using pre-C++20 headers," but there are some KEY DIFFERENCES! Reading (and understanding) what the errors are is a KEY STEP.
Last edited on
You want to understand modules, then I'll recommend a book you buy and read. Religiously.

https://www.amazon.com/gp/product/1484258835/

The source code for the books examples are available online, in module/non-module form. There is also an additional appendix chapter online as a PDF that explains in detail about header/module file linkage. The book is worth the price, the code and PDF are a very nice addition to the book.

There are several other C++20 books I could recommend, as eBooks.
A note for users of VS2019. VS2019 doesn't like modules with the extension .cppm.

Modules need to have the extension .ixx
thmm wrote:
VS2019 doesn't like modules with the extension .cppm

I just now tried my module example above in VS 2019 and it compiled the .cppm file without a problem.

2019's intellisense is twitchier than 2022's, 2019 shows as errors more code than 2022. But it still will compile and run with nary a problem. When the C++ language standard is set to C++20. Set the standard to C++latest and all the "errors" intellisense reports disappear.

VS 2022 language standard can be set to C++20 and no errors are reported.

Well, one "error" is still reported, 2022 or 2019, no matter what the language standard:
export const double lambda = 1.303577269034296391257;

"an export declaration cannot export a name with internal linkage" An error that doesn't stop successful compilation. *shrug*

I've had more persistent hard-to-resolve issues using .ixx than .cppm. VS2022 or 2019.
math.cppm
1
2
export module math;
export auto square(const auto& x) { return x * x; } 


That's strange.
Language standard: Preview - Features from the Latest C++ Working Draft (/std:c++latest)
When I rename math.ixx to math.cppm I get the following errors:
math.cppm(1,1): error C3378: a declaration can be exported only from a module interface unit
math.cppm(1,19): error C2230: could not find module 'math'
math.cppm(3,1): error C3378: a declaration can be exported only from a module interface unit

It doesn't work either with ISO C++20 Standard (/std:c++20)
VS 2019 can be twitchy when it comes to modules, one reason why I prefer 2022. Less issues in my experience.

When I rename math.ixx to math.cppm I get the following errors

You could/should force a full recompile now that you've changed the extension from .ixx to .cppm. Close the project and reopen, and do the full recompile.

If that doesn't work another workaround is to delete the .cppm file from the project and add a new .cppm from the start, copying the code from the old file to the new.

2019 will happily consume .cppm module interface files, after giving it a swift kick in the arse from time to time.

This is MS we are talking about, after all.

By the wording of the error(s) I'd bet VS doesn't recognize the .cppm file as a module interface file, it probably "sees" it as an internal partition file or regular non-module .cpp file.

Are you using command-line compiling and not the IDE? That can also be an issue. I use the IDE. If you are using the IDE check the file's property pages.

Learning how to use modules is enough of a PITA without the distractions VS can sometimes throw at ya with intellisense and other "errors."

The industry is gravitating towards .cppm instead of the MS idea of .ixx. Nice that MS does support the usage, if only in the breach.

.cppm/.ixx is NOT a required extension, it merely informs the IDE and the programmer what the file is to be used for. Manually editing via the file's property pages in the IDE can be done. Internal partition files need to be manually designated in the IDE as an internal partition file, or you get errors up the wazoo.

And don't get me started on the import std.core; muck-up. That makes using modules a major "bang head on desk" frustration.

MS's documentation on using modules leaves a lot to be desired. I had unsolvable problems until I got a book on C++20 and plowed my way through it. That made it easier to deal with the minutiae of modules.

Beginning C++ 20: From Novice to Professional From Novice to Professional
https://www.amazon.com/gp/product/1484258835/
You could/should force a full recompile now that you've changed the extension from .ixx to .cppm. Close the project and reopen, and do the full recompile.
If that doesn't work another workaround is to delete the .cppm file from the project and add a new .cppm from the start, copying the code from the old file to the new.


I did but still the same error messages.

Are you using command-line compiling and not the IDE?
IDE, I have never used command-line in VS

I give up now, surrender to MS and name my modules as .ixx.
Well, I believe you are giving up on something I know works. But not my choice to make. :)

Using modules isn't a make-or-break priority to me at this time, there is very little code out in the wild that does use them, other than half-arsed examples of little actual practical utility.

But I won't neglect using them if at all possible when doing so makes sense for my own uses.

I've created several smallish pre-C++20 header-only libraries in the past I use in my code that for gits and shiggles I "modularized". Didn't require a whole lot of rewriting.

I'd recommend if at all possible getting and using VS 2022. It isn't as twitchy as 2019 in my experience. 2019 can get all wee-weed up on things other than modules.

As I'm sure you know it requires a 64-bit CPU, it won't run on 32-bit. :) (Said this more to a potential any-mouse reader than you, thmm)

Eventually 2019 will go the way of VS 2015/2017. Relics that are just space hogs on one's HD. I keep my copy of 2019 updated though I rarely use it.

Pax!

One last random thought, when/if using modules (and other C++20 features) in 2019 always use c++latest instead of C++20. Until a fairly recent 2022 update to use a lot of C++20 features required c++latest. Trying to do a reverse range-based for loop is one example. Though for reasons that didn't make sense from the errors. Something like "ranges requires concepts" or something like that.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import <iostream>;
import <string>;
import <ranges>;

int main()
{
   std::string str { "C++ is Cool!" };

   std::cout << str << '\n';

   // old school for loop
   for (size_t i { }; i < str.size(); ++i) { std::cout << str[i] << ' '; }
   std::cout << '\n';

   // for loop using const iterators
   for (auto itr { str.cbegin() }; itr != str.cend(); ++itr) { std::cout << *itr << ' '; }
   std::cout << '\n';

   // https://en.cppreference.com/w/cpp/language/range-for
   for (const auto& itr : str) { std::cout << itr << ' '; }
   std::cout << "\n\n";

   // old school reverse for loop
   for (size_t i { str.size() }; i > 0; --i) { std::cout << str[i - 1] << ' '; }
   std::cout << '\n';

   // reverse for loop with const iterators
   for (auto itr { str.crbegin() }; itr != str.crend(); ++itr) { std::cout << *itr << ' '; }
   std::cout << '\n';

   // https://www.fluentcpp.com/2020/02/11/reverse-for-loops-in-cpp/
   for (const auto& itr : str | std::views::reverse) { std::cout << itr << ' '; }
   std::cout << "\n\n";

   // range-based for loops work with regular arrays as well
   int arr[ ] { 5, 10, 15, 20, 25 };

   for (const auto& itr : arr) { std::cout << itr << ' '; }
   std::cout << '\n';

   for (const auto& itr : arr | std::views::reverse) { std::cout << itr << ' '; }
   std::cout << '\n';
}
M'ok, this is a major long shot, but something to check. Check your VS 2019 installation for "C++ modules for v142 build tools (x64/x86 - experimental)".....

If that isn't installed do so. :)

It is also something to check in VS 2022. For v143 build tools, of course.
Last edited on
Topic archived. No new replies allowed.