Modules are a great new feature of C++ 20. We have switched away from using #include files to using modules in our Cadifra UML Editor project.

Modules consist of a primary module interface unit (a source file with the extension .ixx for the MSVC compiler) and zero or more module implementation units (source files with extension .cpp).

Module names and C++ namespace names are orthogonal, which means that they don’t relate to each other. You can have both a namespace foo and a module named foo.

Module names are typically made of words separated by dots, e.g.

export module Canvas.Group;

which defines a module interface unit with the name Canvas.Group. In this interface unit we have defined the namespace Canvas:

namespace Canvas
{

export class Group
{
    ...
};

}

Member functions of the class Canvas::Group can – for example – be implemented in one or more implementation units (.cpp files). Each of these contain the module keyword – without export:

module Canvas.Group;

One thing to note is that – for example – helper functions defined in the implementation units are still best placed inside unnamed namespaces, as they might otherwise collide with names in other implementation units:

namespace
{

int helper(int a, int b)
{
    ....
}

}

Otherwise, if there is another function with the same name in a different implementation unit, the linker will complain about duplicate symbols:

3>Editor.lib(WindowImp_Cmds.obj) : error LNK2005: "int __cdecl Editor::helper(int,int)" (?helper@Editor@@YAHHH@Z) already defined in Editor.lib(WindowImp_CmdWindow.obj)
3>... : fatal error LNK1169: one or more multiply defined symbols found