C++ modules

Hello,

this is the last post of this year !

The modern C++ language features include modules.

As everybody knows, C++ inherits C header files, which, originally, were a convenient way to separate declarations from definitions.

Unfortunately, it has many drawbacks: longer compilation time (the same .h file is read multiple times, whenever it’s included in a source file), order dependencies (declarations and macros in the first included .h file may affect the following .h files), redefinitions (the code in the header file, if included multiple times, should be preceded by a #pragma once or enclosed in #ifndef FILENAME #define FILENAME…#endif).

In C++20 modularity is supported directly by the language itself. See the following example.


import std;
export module Test;

export class Test
{
public:
	Test();
	Test(int x);
	void set(int x);
	const int get();
	friend std::ostream& operator<<(std::ostream &str, const Test& t);
private:
	int iVal;
};

Test::Test() : iVal{0} {}			// Ctor
Test::Test(int x) : iVal{x} {}		// Ctor
void Test::set(int x)				// set()
{
	iVal = x;
}
const int Test::get()				// get()
{
	return iVal;
}

export bool operator==(Test& t1, Test& t2)
{
if(t1.get() == t2.get())
	return true;
return false;
}

export std::ostream& operator<<(std::ostream &str, const Test& t)
	{
	str << t.iVal;
	return str;
	}



import Test;

//#include <iostream>
import std;
//import std.compat;

using std::endl;
using std::cout;


int main()
{
    Test t1(5);
    cout << endl << "Hello World!";
    cout << endl << "Test t1 = "  << t1 << endl;

}

The Test class declaration, and all other declarations needed, are preceded by the export keyword; before all these declarations, the line export module MyModule; defines and names the user’s module. This module is imported with the simple line import MyModule; at the beginning of the file where it’s needed.

Modules have some advantages over classic header files: a module is compiled once; a file included or imported into a module has a local scope (avoiding multiple inclusions); modules can be imported in any order. Macros should not be used anymore.

What happens with the headers of the standard library? Up to C++20, we must keep on using traditional #include <library_name> lines. But with C++23 the complete standard library can be referred to with the simple import std; line.

With Visual Studio 2022, some extra care must be paid to set the solution properties, before building it (see image): language standard must be C++20 or newer; standard library modules (ISO C++ 23) must be compiled.

Hoping this could help develop better software,
I wish you a happy new year 2024 !