A namespace groups names so that they do not collide. A module, new in C++20, is a unit of compilation with its own interface. The two are separate ideas: a module does not create a namespace, and a namespace can extend across several modules.
Namespaces
namespace-definition:
[inline] namespace [attribute-specifier-seq] identifier { namespace-body }
[inline] namespace [attribute-specifier-seq] { namespace-body }
namespace enclosing-namespace-specifier :: [inline] identifier { namespace-body }
A namespace can be reopened any number of times, in any file [namespace.def]. Names
at file level are in the global namespace, written ::name.
| Form | Example | Effect | Since |
|---|---|---|---|
| Named | namespace lib { } | Groups names under lib:: | C++98 |
| Unnamed | namespace { } | Members have internal linkage, and are visible only in this translation unit [namespace.unnamed] | C++98 |
| Inline | inline namespace v2 { } | Members are treated as members of the enclosing namespace too. Used for library versioning | C++11 |
| Nested definition | namespace a::b::c { } | Shorthand for nesting | C++17 |
| Nested with inline | namespace a::inline b { } | Marks one level as inline | C++20 |
| Alias | namespace fs = std::filesystem; | A second name for a namespace [namespace.alias] | C++98 |
using
| Form | Example | Effect | Section |
|---|---|---|---|
| Using-declaration | using std::string; | Brings one name into this scope | [namespace.udecl] |
| Several names (C++17) | using std::string, std::vector; | The same, for each name | [namespace.udecl] |
| Using-directive | using namespace std; | Makes all names of a namespace visible for unqualified lookup, as if declared in the nearest enclosing common namespace | [namespace.udir] |
| Using-enum (C++20) | using enum Colour; | Brings a scoped enumeration’s names in | [enum.udecl] |
| Alias (C++11) | using Id = std::uint64_t; | A type alias | [dcl.typedef] |
A using directive in a header affects every file that includes it, so it
is best kept to function bodies and source files. In a class, a using-declaration
names a member of a base class; see
Inheritance.
Name lookup
When a name is used, the compiler finds its declaration by name lookup [basic.lookup].
| Kind | Applies to | Searches |
|---|---|---|
| Unqualified | name | Each enclosing scope, from the innermost out; stops at the first scope that has the name [basic.lookup.unqual] |
| Qualified | scope::name | The named class or namespace [basic.lookup.qual] |
| Argument-dependent | An unqualified function call | Also the namespaces associated with its arguments [basic.lookup.argdep] |
| Class member | a.name, p->name | The class and its bases [class.member.lookup] |
Because lookup stops at the first scope containing the name, a declaration in an inner scope hides declarations of the same name in outer scopes, even if their types differ. Lookup happens before overload resolution and before access checks.
In a template, dependent names are looked up at instantiation. See Templates.
Argument-dependent lookup
For an unqualified call, argument-dependent lookup (ADL) adds functions from namespaces related to the arguments’ types [basic.lookup.argdep].
| Argument type | Associated entities |
|---|---|
| Class | The class, its direct and indirect base classes, and the class of which it is a member |
| Class template specialisation | As above, plus the types and templates of its template arguments |
| Enumeration | The enumeration’s enclosing namespace, or the class it is a member of |
| Pointer, reference or array | As for the type it refers to |
| Function type | The parameter and return types |
| Fundamental type | None |
ADL does not happen if ordinary lookup finds a class member, a block-scope
function declaration that is not a using-declaration, or a name that
is not a function or function template.
namespace geo {
struct Point { int x, y; };
Point operator+(Point a, Point b);
void print(Point p);
}
geo::Point p{1, 2}, q{3, 4};
auto r = p + q; // geo::operator+ found by ADL
print(r); // geo::print found by ADL
using std::swap; // the customary idiom
swap(p, q); // calls a swap in geo if there is one, otherwise std::swap
A friend function defined only inside a class can be found only by ADL. Such a hidden friend does not add to the overload set of ordinary lookup.
Modules
A module (C++20) is a set of module units, translation units that share a module name [module]. Unlike a header, a module is compiled once, and what it exports is imported by name, not pasted as text. Macros in a named module do not leak out.
module-declaration:
[export-keyword] module-keyword module-name [module-partition] [attribute-specifier-seq] ;
module-name:
[module-name-qualifier] identifier
module-partition:
: [module-name-qualifier] identifier
translation-unit:
[global-module-fragment] module-declaration [declaration-seq] [private-module-fragment]
Module names may contain dots, which have no meaning and do not imply a hierarchy. A named module needs exactly one primary module interface unit [module.unit].
Kinds of module unit
| Kind | Declaration | Purpose |
|---|---|---|
| Primary interface unit | export module M; | The module’s interface. Must be exactly one |
| Implementation unit | module M; | Definitions. Implicitly imports the module’s interface. Cannot be imported |
| Interface partition | export module M:part; | Part of the interface. Must be re-exported by the primary interface |
| Implementation partition | module M:part; | An internal part that other units of the module can import |
// greet.cppm
module; // global module fragment: for #include only
#include <cstdio>
export module greet; // primary module interface unit
import <string>;
export std::string greet(const std::string& name);
export namespace lib {
int version();
}
// greet.cpp
module greet; // an implementation unit
std::string greet(const std::string& name) { return "Hello, " + name; }
int lib::version() { return 1; }
// main.cpp
import greet;
int main() { return lib::version(); }
export
export makes a declaration part of the module’s interface
[module.interface]. It may be used on a single declaration, on a namespace, or on a
block. It can appear only in a module interface unit, and cannot be used on anything with
internal linkage. A name that is not exported has module linkage: it is
visible to the module’s other units but not to importers.
export int add(int a, int b);
export class Widget { };
export { void one(); void two(); }
export namespace api { void three(); }
export import other; // re-exports another module
import
An import declaration [module.import] appears only at global namespace scope. In a
module unit, every import must come before all other declarations, directly after
the module declaration.
| Form | Imports |
|---|---|
import M; | A named module |
import :part; | A partition of the current module |
import <vector>; | A header unit |
import std; | The whole standard library in namespace std (C++23) |
import std.compat; | As std, plus the C names in the global namespace (C++23) |
An import does not bring in macros from a named module. Importing a module does not bring names into scope by itself: exported names are just visible to lookup, in their own namespaces.
Module fragments
- Global module fragment.
module;at the start of the file, before the module declaration. It may contain only preprocessing directives, and is how legacy#includes reach a module unit [module.global.frag]. - Private module fragment.
module :private;at the end of a primary interface unit. Its content is not reachable from importers, so it cannot affect them. A unit with a private fragment must be the only unit of its module [module.private.frag].
Visibility and reachability
A visible declaration can be found by name. A reachable declaration
is one whose semantic properties, such as the definition of a class, are available
[module.reach]. An exported function can return a type that is not exported. The
caller then cannot name the type but can use it through auto.
Header units
import <header>; or import "header"; imports a header
compiled as a header unit [module.import]. Unlike a named module, a header
unit exports its macros. Unlike #include, it does not see the macros of
the file that imports it. Which headers can be imported this way is
implementation-defined, apart from the standard C++ library headers
[headers].
Module file forms
The standard does not define a file extension for modules. Compilers have settled on these conventions:
| Compiler | Module source | Compiled interface |
|---|---|---|
| GCC | Any C++ extension; .cc, .cpp and .cxx are common | .gcm, kept in a gcm.cache folder by default |
| Clang | .cppm, .ccm, .cxxm, .c++m | .pcm |
| MSVC | .ixx for interfaces, or any extension with /interface | .ifc |
A compiled interface is a binary file private to one compiler, and generally to its version and options. It is not a distribution format. A module interface must be built before any translation unit that imports it, so a build system has to scan sources for their import dependencies first.