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
module-name-qualifier: identifier . module-name-qualifier identifier .
Translation unit #1:
export module A; export import :Foo; export int baz();
Translation unit #2:
export module A:Foo; import :Internals; export int foo() { return 2 * (bar() + 1); }
Translation unit #3:
module A:Internals; int bar();
Translation unit #4:
module A; import :Internals; int bar() { return baz() - 10; } int baz() { return 30; }
Translation unit #1:
module B:Y; // does not implicitly import B int y();
Translation unit #2:
export module B; import :Y; // OK, does not create interface dependency cycle int n = y();
Translation unit #3:
module B:X1; // does not implicitly import B int &a = n; // error: n not visible here
Translation unit #4:
module B:X2; // does not implicitly import B import B; int &b = n; // OK
Translation unit #5:
module B; // implicitly imports B int &c = n; // OK— end example
export-declaration: export declaration export { declaration-seq } export-keyword module-import-declaration
Source file "a.h":
export int x;
Translation unit #1:
module; #include "a.h" // error: declaration of x is not in the // purview of a module interface unit export module M; export namespace {} // error: does not introduce any names export namespace { int a1; // error: export of name with internal linkage } namespace { export int a2; // error: export of name with internal linkage } export static int b; // error: b explicitly declared static export int f(); // OK export namespace N { } // OK export using namespace N; // error: does not declare a name— end example
Source file "b.h":
int f();
Importable header "c.h":
int g();
Translation unit #1:
export module X; export int h();
Translation unit #2:
module; #include "b.h" export module M; import "c.h"; import X; export using ::f, ::g, ::h; // OK struct S; export using ::S; // error: S has module linkage namespace N { export int h(); static int h(int); // #1 } export using N::h; // error: #1 has internal linkage— end example
export module M; struct S; export using T = S; // OK, exports name T denoting type S— end example
export module M; struct S { int n; }; typedef S S; export typedef S S; // OK, does not redeclare an entity export struct S; // error: exported declaration follows non-exported declaration— end example
Interface unit of M:
export module M; export struct X { static void f(); struct Y { }; }; namespace { struct S { }; } export void f(S); // OK struct T { }; export T id(T); // OK export struct A; // A exported as incomplete export auto rootFinder(double a) { return [=](double x) { return (x + a/x)/2; }; } export const int n = 5; // OK, n has external linkage
Implementation unit of M:
module M; struct A { int value; };
Main program:
import M; int main() { X::f(); // OK, X is exported and definition of X is reachable X::Y y; // OK, X::Y is exported as a complete type auto f = rootFinder(2); // OK return A{45}.value; // error: A is incomplete }— end example
Interface unit of M:
export module M; static int f(); // #1 export int f(); // error: #1 gives internal linkage struct S; // #2 export struct S; // error: #2 gives module linkage namespace { namespace N { extern int x; // #3 } } export int N::x; // error: #3 gives internal linkage— end example
export module M; export namespace N { int x; // OK static_assert(1 == 1); // error: does not declare a name }— end example
module-import-declaration: import-keyword module-name attribute-specifier-seq ; import-keyword module-partition attribute-specifier-seq ; import-keyword header-name attribute-specifier-seq ;
Translation unit #1:
module M:Part;
Translation unit #2:
export module M; export import :Part; // error: exported partition :Part is an implementation unit— end example
module M; import M; // error: cannot import M in its own unit— end example
Interface unit of M1:
export module M1; import M2;
Interface unit of M2:
export module M2; import M3;
Interface unit of M3:
export module M3; import M1; // error: cyclic interface dependency— end example
global-module-fragment: module-keyword ; declaration-seq
postfix-expression ( expression-list )whose postfix-expression denotes a dependent name, or for an operator expression whose operator denotes a dependent name, and D is found by name lookup for the corresponding name in an expression synthesized from E by replacing each type-dependent argument or operand with a value of a placeholder type with no associated namespaces or entities, or
const int size = 2; int ary1[size]; // unspecified whether size is decl-reachable from ary1 constexpr int identity(int x) { return x; } int ary2[identity(2)]; // unspecified whether identity is decl-reachable from ary2 template<typename> struct S; template<typename, int> struct S2; constexpr int g(int); template<typename T, int N> S<S2<T, g(N)>> f(); // S, S2, g, and :: are decl-reachable from f template<int N> void h() noexcept(g(N) == N); // g and :: are decl-reachable from h— end example
Source file "foo.h":
namespace N { struct X {}; int d(); int e(); inline int f(X, int = d()) { return e(); } int g(X); int h(X); }
Module M interface:
module; #include "foo.h" export module M; template<typename T> int use_f() { N::X x; // N::X, N, and :: are decl-reachable from use_f return f(x, 123); // N::f is decl-reachable from use_f, // N::e is indirectly decl-reachable from use_f // because it is decl-reachable from N::f, and // N::d is decl-reachable from use_f // because it is decl-reachable from N::f // even though it is not used in this call } template<typename T> int use_g() { N::X x; // N::X, N, and :: are decl-reachable from use_g return g((T(), x)); // N::g is not decl-reachable from use_g } template<typename T> int use_h() { N::X x; // N::X, N, and :: are decl-reachable from use_h return h((T(), x)); // N::h is not decl-reachable from use_h, but // N::h is decl-reachable from use_h<int> } int k = use_h<int>(); // use_h<int> is decl-reachable from k, so // N::h is decl-reachable from k
Module M implementation:
module M; int a = use_f<int>(); // OK int b = use_g<int>(); // error: no viable function for call to g; // g is not decl-reachable from purview of // module M's interface, so is discarded int c = use_h<int>(); // OK— end example
private-module-fragment: module-keyword : private ; declaration-seq
export module A; export inline void fn_e(); // error: exported inline function fn_e not defined // before private module fragment inline void fn_m(); // OK, module-linkage inline function static void fn_s(); export struct X; export void g(X *x) { fn_s(); // OK, call to static function in same translation unit fn_m(); // OK, call to module-linkage inline function } export X *factory(); // OK module :private; struct X {}; // definition not reachable from importers of A X *factory() { return new X (); } void fn_e() {} void fn_m() {} void fn_s() {}— end example
Translation unit #1:
export module stuff; export template<typename T, typename U> void foo(T, U u) { auto v = u; } export template<typename T, typename U> void bar(T, U u) { auto v = *u; }
Translation unit #2:
export module M1; import "defn.h"; // provides struct X {}; import stuff; export template<typename T> void f(T t) { X x; foo(t, x); }
Translation unit #3:
export module M2; import "decl.h"; // provides struct X; (not a definition) import stuff; export template<typename T> void g(T t) { X *x; bar(t, x); }
Translation unit #4:
import M1; import M2; void test() { f(0); g(0); }
Translation unit #1:
export module M:A; export struct B;
Translation unit #2:
module M:B; struct B { operator int(); };
Translation unit #3:
module M:C; import :A; B b1; // error: no reachable definition of struct B
Translation unit #4:
export module M; export import :A; import :B; B b2; export void f(B b = B());
Translation unit #5:
module X; import M; B b3; // error: no reachable definition of struct B void g() { f(); } // error: no reachable definition of struct B— end example
Translation unit #1:
export module A; struct X {}; export using Y = X;
Translation unit #2:
module B; import A; Y y; // OK, definition of X is reachable X x; // error: X not visible to unqualified lookup— end example