1. | An implementation shall support input files
that are a sequence of UTF-8 code units (UTF-8 files). It may also support
an implementation-defined set of other kinds of input files, and,
if so, the kind of an input file is determined in
an implementation-defined manner
that includes a means of designating input files as UTF-8 files,
independent of their content.
If an input file is determined to be a UTF-8 file,
then it shall be a well-formed UTF-8 code unit sequence and
it is decoded to produce a sequence of Unicode8
scalar values. A sequence of translation character set elements ([lex.charset]) is then formed
by mapping each Unicode scalar value
to the corresponding translation character set element. In the resulting sequence,
each pair of characters in the input sequence consisting of
U+000d carriage return followed by U+000a line feed,
as well as each
U+000d carriage return not immediately followed by a U+000a line feed,
is replaced by a single new-line character. For any other kind of input file supported by the implementation,
characters are mapped, in an
implementation-defined manner,
to a sequence of translation character set elements,
representing end-of-line indicators as new-line characters. |
2. | Each sequence of a backslash character (\)
immediately followed by
zero or more whitespace characters other than new-line followed by
a new-line character is deleted, splicing
physical source lines to form logical source lines. Only the last
backslash on any physical source line shall be eligible for being part
of such a splice. [Note 2: — end note]
A source file that is not empty and that (after splicing)
does not end in a new-line character
shall be processed as if an additional new-line character were appended
to the file. |
3. | The source file is decomposed into preprocessing
tokens ([lex.pptoken]) and sequences of whitespace characters
(including comments).
Each comment ([lex.comment]) is replaced by one space character. New-line characters are
retained. Whether each nonempty sequence of whitespace characters other
than new-line is retained or replaced by one space character is
unspecified. As characters from the source file are consumed
to form the next preprocessing token
(i.e., not being consumed as part of a comment or other forms of whitespace),
except when matching a
c-char-sequence,
s-char-sequence,
r-char-sequence,
h-char-sequence, or
q-char-sequence,
universal-character-names are recognized ([lex.universal.char]) and
replaced by the designated element of the translation character set ([lex.charset]). The process of dividing a source file's
characters into preprocessing tokens is context-dependent. [Example 1: — end example] |
4. | Preprocessing directives ([cpp]) are executed, macro invocations are
expanded ([cpp.replace]), and _Pragma unary operator expressions are executed ([cpp.pragma.op]). A #include preprocessing directive ([cpp.include]) causes the named header or
source file to be processed from phase 1 through phase 4, recursively. All preprocessing directives are then deleted. |
5. | For a sequence of two or more adjacent string-literal preprocessing tokens,
a common encoding-prefix is determined
as specified in [lex.string]. Each such string-literal preprocessing token is then considered to have
that common encoding-prefix. |
6. | |
7. | Each preprocessing token is converted into a token ([lex.token]). Whitespace characters separating tokens are no longer significant. The resulting tokens constitute a translation unit and
are syntactically and
semantically analyzed as a translation-unit ([basic.link]) and
translated. [Note 3: The process of analyzing and translating the tokens can occasionally
result in one token being replaced by a sequence of other
tokens ([temp.names]). — end note]
It is
implementation-defined
whether the sources for
module units and header units
on which the current translation unit has an interface
dependency ([module.unit], [module.import])
are required to be available. [Note 4: Source files, translation
units and translated translation units need not necessarily be stored as
files, nor need there be any one-to-one correspondence between these
entities and any external representation. The description is conceptual
only, and does not specify any particular implementation. — end note] |
8. | Translated translation units and instantiation units are combined
as follows:
Each translated translation unit is examined to
produce a list of required instantiations. [Note 6: This can include
instantiations which have been explicitly
requested ([temp.explicit]). — end note]
The definitions of the
required templates are located. It is implementation-defined whether the
source of the translation units containing these definitions is required
to be available.
All the required instantiations
are performed to produce
instantiation units.
The
program is ill-formed if any instantiation fails. |
9. |
character | glyph | |
U+0009 | character tabulation | |
U+000b | line tabulation | |
U+000c | form feed | |
U+0020 | space | |
U+000a | line feed | new-line |
U+0021 | exclamation mark | ! |
U+0022 | quotation mark | " |
U+0023 | number sign | # |
U+0024 | dollar sign | $ |
U+0025 | percent sign | % |
U+0026 | ampersand | & |
U+0027 | apostrophe | ' |
U+0028 | left parenthesis | ( |
U+0029 | right parenthesis | ) |
U+002a | asterisk | * |
U+002b | plus sign | + |
U+002c | comma | , |
U+002d | hyphen-minus | - |
U+002e | full stop | . |
U+002f | solidus | / |
U+0030 .. U+0039 | digit zero .. nine | 0 1 2 3 4 5 6 7 8 9 |
U+003a | colon | : |
U+003b | semicolon | ; |
U+003c | less-than sign | < |
U+003d | equals sign | = |
U+003e | greater-than sign | > |
U+003f | question mark | ? |
U+0040 | commercial at | @ |
U+0041 .. U+005a | latin capital letter a .. z | A B C D E F G H I J K L M |
N O P Q R S T U V W X Y Z | ||
U+005b | left square bracket | [ |
U+005c | reverse solidus | \ |
U+005d | right square bracket | ] |
U+005e | circumflex accent | ^ |
U+005f | low line | _ |
U+0060 | grave accent | ` |
U+0061 .. U+007a | latin small letter a .. z | a b c d e f g h i j k l m |
n o p q r s t u v w x y z | ||
U+007b | left curly bracket | { |
U+007c | vertical line | | |
U+007d | right curly bracket | } |
U+007e | tilde | ~ |
final | import | post | replaceable_if_eligible |
override | module | pre | trivially_relocatable_if_eligible |
alignas | constinit | extern | protected | throw |
alignof | const_cast | false | public | true |
asm | continue | float | register | try |
auto | contract_assert | for | reinterpret_cast | typedef |
bool | co_await | friend | requires | typeid |
break | co_return | goto | return | typename |
case | co_yield | if | short | union |
catch | decltype | inline | signed | unsigned |
char | default | int | sizeof | using |
char8_t | delete | long | static | virtual |
char16_t | do | mutable | static_assert | void |
char32_t | double | namespace | static_cast | volatile |
class | dynamic_cast | new | struct | wchar_t |
concept | else | noexcept | switch | while |
const | enum | nullptr | template | |
consteval | explicit | operator | this | |
constexpr | export | private | thread_local |
and | and_eq | bitand | bitor | compl | not |
not_eq | or | or_eq | xor | xor_eq |
integer-literal other than decimal-literal | ||
none | int | int |
long int | unsigned int | |
long long int | long int | |
unsigned long int | ||
long long int | ||
unsigned long long int | ||
u or U | unsigned int | unsigned int |
unsigned long int | unsigned long int | |
unsigned long long int | unsigned long long int | |
l or L | long int | long int |
long long int | unsigned long int | |
long long int | ||
unsigned long long int | ||
Both u or U | unsigned long int | unsigned long int |
and l or L | unsigned long long int | unsigned long long int |
ll or LL | long long int | long long int |
unsigned long long int | ||
Both u or U | unsigned long long int | unsigned long long int |
and ll or LL | ||
z or Z | the signed integer type corresponding | the signed integer type |
to std::size_t ([support.types.layout]) | corresponding to std::size_t | |
std::size_t | ||
Both u or U | std::size_t | std::size_t |
and z or Z |
Encoding | Kind | Type | Associated char- | Example |
prefix | acter encoding | |||
none | char | ordinary literal | 'v' | |
multicharacter literal | int | encoding | 'abcd' | |
L | wchar_t | wide literal | L'w' | |
encoding | ||||
u8 | char8_t | UTF-8 | u8'x' | |
u | char16_t | UTF-16 | u'y' | |
U | char32_t | UTF-32 | U'z' |
character | ||
U+000a | line feed | \n |
U+0009 | character tabulation | \t |
U+000b | line tabulation | \v |
U+0008 | backspace | \b |
U+000d | carriage return | \r |
U+000c | form feed | \f |
U+0007 | alert | \a |
U+005c | reverse solidus | \\ |
U+003f | question mark | \? |
U+0027 | apostrophe | \' |
U+0022 | quotation mark | \" |
type | |
none | double |
f or F | float |
l or L | long double |
f16 or F16 | std::float16_t |
f32 or F32 | std::float32_t |
f64 or F64 | std::float64_t |
f128 or F128 | std::float128_t |
bf16 or BF16 | std::bfloat16_t |
Enco- | Kind | Type | Associated | Examples |
ding | character | |||
prefix | encoding | |||
none | array of n const char | ordinary literal encoding | "ordinary string" R"(ordinary raw string)" | |
L | array of n const wchar_t | wide literal encoding | L"wide string" LR"w(wide raw string)w" | |
u8 | array of n const char8_t | UTF-8 | u8"UTF-8 string" u8R"x(UTF-8 raw string)x" | |
u | array of n const char16_t | UTF-16 | u"UTF-16 string" uR"y(UTF-16 raw string)y" | |
U | array of n const char32_t | UTF-32 | U"UTF-32 string" UR"z(UTF-32 raw string)z" |
Translation unit #1:export module Q; export int sq(int i) { return i*i; }
Translation unit #2:export module R; export import Q;
Translation unit #3:import R; int main() { return sq(9); } // OK, sq from module Q — end example]
Translation unit #1:export module M; namespace R { export struct X {}; export void f(X); } namespace S { export void f(R::X, R::X); }
Translation unit #2:export module N; import M; export R::X make(); namespace R { static int g(X); } export template<typename T, typename U> void apply(T t, U u) { f(t, u); g(t); }
Translation unit #3:module Q; import N; namespace S { struct Z { template<typename T> operator T(); }; } void test() { auto x = make(); // OK, decltype(x) is R::X in module M R::f(x); // error: R and R::f are not visible here f(x); // OK, calls R::f from interface of M f(x, S::Z()); // error: S::f in module M not considered // even though S is an associated namespace apply(x, S::Z()); // error: S::f is visible in instantiation context, but // R::g has internal linkage and cannot be used outside TU #2 } — end example]
"decls.h":int f(); // #1, attached to the global module int g(); // #2, attached to the global module
Module interface of M:module; #include "decls.h" export module M; export using ::f; // OK, does not declare an entity, exports #1 int g(); // error: matches #2, but attached to M export int h(); // #3 export int k(); // #4
Other translation unit:import M; static int h(); // error: matches #3 int k(); // error: matches #4 — end example]
Translation unit #1:export module A; static void f() {} inline void it() { f(); } // error: is an exposure of f static inline void its() { f(); } // OK template<int> void g() { its(); } // OK template void g<0>(); decltype(f) *fp; // error: f (though not its type) is TU-local auto &fr = f; // OK constexpr auto &fr2 = fr; // error: is an exposure of f constexpr static auto fp2 = fr; // OK struct S { void (&ref)(); } s{f}; // OK, value is TU-local constexpr extern struct W { S &s; } wrap{s}; // OK, value is not TU-local static auto x = []{f();}; // OK auto x2 = x; // error: the closure type is TU-local int y = ([]{f();}(),0); // error: the closure type is not TU-local int y2 = (x,0); // OK namespace N { struct A {}; void adl(A); static void adl(int); } void adl(double); inline void h(auto x) { adl(x); } // OK, but certain specializations are exposures
Translation unit #2:module A; void other() { g<0>(); // OK, specialization is explicitly instantiated g<1>(); // error: instantiation uses TU-local its h(N::A{}); // error: overload set contains TU-local N::adl(int) h(0); // OK, calls adl(double) adl(N::A{}); // OK; N::adl(int) not found, calls N::adl(N::A) fr(); // OK, calls f constexpr auto ptr = fr; // error: fr is not usable in constant expressions here } — end example]
Parameter | float16_t | float32_t | float64_t | float128_t | bfloat16_t |
ISO/IEC 60559 name | binary16 | binary32 | binary64 | binary128 | |
k, storage width in bits | 16 | 32 | 64 | 128 | 16 |
p, precision in bits | 11 | 24 | 53 | 113 | 8 |
emax, maximum exponent | 15 | 127 | 1023 | 16383 | 127 |
w, exponent field width in bits | 5 | 8 | 11 | 15 | 8 |
Specifier(s) | Type |
the type named | |
the type as defined in [temp.names] | |
the type as defined in [dcl.type.decltype] | |
the type as defined in [dcl.type.pack.index] | |
the type as defined in [dcl.spec.auto] | |
the type as defined in [dcl.type.class.deduct] | |
char | “char” |
unsigned char | “unsigned char” |
signed char | “signed char” |
char8_t | “char8_t” |
char16_t | “char16_t” |
char32_t | “char32_t” |
bool | “bool” |
unsigned | “unsigned int” |
unsigned int | “unsigned int” |
signed | “int” |
signed int | “int” |
int | “int” |
unsigned short int | “unsigned short int” |
unsigned short | “unsigned short int” |
unsigned long int | “unsigned long int” |
unsigned long | “unsigned long int” |
unsigned long long int | “unsigned long long int” |
unsigned long long | “unsigned long long int” |
signed long int | “long int” |
signed long | “long int” |
signed long long int | “long long int” |
signed long long | “long long int” |
long long int | “long long int” |
long long | “long long int” |
long int | “long int” |
long | “long int” |
signed short int | “short int” |
signed short | “short int” |
short int | “short int” |
short | “short int” |
wchar_t | “wchar_t” |
float | “float” |
double | “double” |
long double | “long double” |
void | “void” |
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]
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: namespace has 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; // OK — 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]
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 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 M3 →M1 →M2 →M3 — 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]
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: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:import A; Y y; // OK, definition of X is reachable X x; // error: X not visible to unqualified lookup — end example]