{ expression }indicates an optional expression enclosed in braces.
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 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 0 1 2 3 4 5 6 7 8 9 _ { } [ ] # ( ) < > % : ; . ? * + - / ^ & | ~ ! = , \ " '
hex-quad: hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit
universal-character-name: \u hex-quad \U hex-quad hex-quad
preprocessing-token: header-name import-keyword module-keyword export-keyword identifier pp-number character-literal user-defined-character-literal string-literal user-defined-string-literal preprocessing-op-or-punc each non-white-space character that cannot be one of the above
encoding-prefix R raw-string
#define R "x" const char* s = R"y"; // ill-formed raw string, not "x" "y"— end example
Alternative | Primary | Alternative | Primary | Alternative | Primary |
<% | { | and | && | and_eq | &= |
%> | } | bitor | | | or_eq | |= |
<: | [ | or | || | xor_eq | ^= |
:> | ] | xor | ^ | not | ! |
%: | # | compl | ~ | not_eq | != |
%:%: | ## | bitand | & |
token: identifier keyword literal operator-or-punctuator
header-name: < h-char-sequence > " q-char-sequence "
h-char-sequence: h-char h-char-sequence h-char
h-char: any member of the source character set except new-line and >
q-char-sequence: q-char q-char-sequence q-char
q-char: any member of the source character set except new-line and "
pp-number: digit . digit pp-number digit pp-number identifier-nondigit pp-number ' digit pp-number ' nondigit pp-number e sign pp-number E sign pp-number p sign pp-number P sign pp-number .
identifier: identifier-nondigit identifier identifier-nondigit identifier digit
identifier-nondigit: nondigit universal-character-name
nondigit: one of 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 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 _
digit: one of 0 1 2 3 4 5 6 7 8 9
00A8 | 00AA | 00AD | 00AF | 00B2-00B5 |
00B7-00BA | 00BC-00BE | 00C0-00D6 | 00D8-00F6 | 00F8-00FF |
0100-167F | 1681-180D | 180F-1FFF | ||
200B-200D | 202A-202E | 203F-2040 | 2054 | 2060-206F |
2070-218F | 2460-24FF | 2776-2793 | 2C00-2DFF | 2E80-2FFF |
3004-3007 | 3021-302F | 3031-D7FF | ||
F900-FD3D | FD40-FDCF | FDF0-FE44 | FE47-FFFD | |
10000-1FFFD | 20000-2FFFD | 30000-3FFFD | 40000-4FFFD | 50000-5FFFD |
60000-6FFFD | 70000-7FFFD | 80000-8FFFD | 90000-9FFFD | A0000-AFFFD |
B0000-BFFFD | C0000-CFFFD | D0000-DFFFD | E0000-EFFFD |
0300-036F | 1DC0-1DFF | 20D0-20FF | FE20-FE2F |
keyword: any identifier listed in Table tab:lex.key import-keyword module-keyword export-keyword
preprocessing-op-or-punc: preprocessing-operator operator-or-punctuator
preprocessing-operator: one of # ## %: %:%:
operator-or-punctuator: one of { } [ ] ( ) <: :> <% %> ; : ... ? :: . .* -> ->* ~ ! + - * / % ^ & | = += -= *= /= %= ^= &= |= == != < > <= >= <=> && || << >> <<= >>= ++ -- , and or xor not bitand bitor compl and_eq or_eq xor_eq not_eq
integer-literal: binary-literal integer-suffix octal-literal integer-suffix decimal-literal integer-suffix hexadecimal-literal integer-suffix
binary-literal: 0b binary-digit 0B binary-digit binary-literal ' binary-digit
octal-literal: 0 octal-literal ' octal-digit
decimal-literal: nonzero-digit decimal-literal ' digit
hexadecimal-literal: hexadecimal-prefix hexadecimal-digit-sequence
binary-digit: one of 0 1
octal-digit: one of 0 1 2 3 4 5 6 7
nonzero-digit: one of 1 2 3 4 5 6 7 8 9
hexadecimal-prefix: one of 0x 0X
hexadecimal-digit-sequence: hexadecimal-digit hexadecimal-digit-sequence ' hexadecimal-digit
hexadecimal-digit: one of 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
integer-suffix: unsigned-suffix long-suffix unsigned-suffix long-long-suffix long-suffix unsigned-suffix long-long-suffix unsigned-suffix
unsigned-suffix: one of u U
long-suffix: one of l L
long-long-suffix: one of ll LL
Kind of integer-literal | base N |
binary-literal | 2 |
octal-literal | 8 |
decimal-literal | 10 |
hexadecimal-literal | 16 |
integer-suffix | decimal-literal | 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 |
character-literal: encoding-prefix ' c-char-sequence '
encoding-prefix: one of u8 u U L
c-char-sequence: c-char c-char-sequence c-char
c-char: any member of the basic source character set except the single-quote ', backslash \, or new-line character escape-sequence universal-character-name
escape-sequence: simple-escape-sequence octal-escape-sequence hexadecimal-escape-sequence
simple-escape-sequence: one of \' \" \? \\ \a \b \f \n \r \t \v
octal-escape-sequence: \ octal-digit \ octal-digit octal-digit \ octal-digit octal-digit octal-digit
hexadecimal-escape-sequence: \x hexadecimal-digit hexadecimal-escape-sequence hexadecimal-digit
new-line | NL(LF) | \n |
horizontal tab | HT | \t |
vertical tab | VT | \v |
backspace | BS | \b |
carriage return | CR | \r |
form feed | FF | \f |
alert | BEL | \a |
backslash | \ | \\ |
question mark | ? | \? |
single quote | ' | \' |
double quote | " | \" |
octal number | ooo | \ooo |
hex number | hhh | \xhhh |
floating-point-literal: decimal-floating-point-literal hexadecimal-floating-point-literal
decimal-floating-point-literal: fractional-constant exponent-part floating-point-suffix digit-sequence exponent-part floating-point-suffix
hexadecimal-floating-point-literal: hexadecimal-prefix hexadecimal-fractional-constant binary-exponent-part floating-point-suffix hexadecimal-prefix hexadecimal-digit-sequence binary-exponent-part floating-point-suffix
fractional-constant: digit-sequence . digit-sequence digit-sequence .
hexadecimal-fractional-constant: hexadecimal-digit-sequence . hexadecimal-digit-sequence hexadecimal-digit-sequence .
exponent-part: e sign digit-sequence E sign digit-sequence
binary-exponent-part: p sign digit-sequence P sign digit-sequence
sign: one of + -
digit-sequence: digit digit-sequence ' digit
floating-point-suffix: one of f l F L
floating-point-suffix | type |
none | |
f or F | |
l or L |
string-literal: encoding-prefix " s-char-sequence " encoding-prefix R raw-string
s-char-sequence: s-char s-char-sequence s-char
s-char: any member of the basic source character set except the double-quote ", backslash \, or new-line character escape-sequence universal-character-name
raw-string: " d-char-sequence ( r-char-sequence ) d-char-sequence "
r-char-sequence: r-char r-char-sequence r-char
r-char: any member of the source character set, except a right parenthesis ) followed by the initial d-char-sequence (which may be empty) followed by a double quote ".
d-char-sequence: d-char d-char-sequence d-char
d-char: any member of the basic source character set except: space, the left parenthesis (, the right parenthesis ), the backslash \, and the control characters representing horizontal tab, vertical tab, form feed, and newline.
const char* p = R"(a\ b c)"; assert(std::strcmp(p, "a\\\nb\nc") == 0);
Source | Means | Source | Means | Source | Means | |||
u"a" | u"b" | u"ab" | U"a" | U"b" | U"ab" | L"a" | L"b" | L"ab" |
u"a" | "b" | u"ab" | U"a" | "b" | U"ab" | L"a" | "b" | L"ab" |
"a" | u"b" | u"ab" | "a" | U"b" | U"ab" | "a" | L"b" | L"ab" |
pointer-literal: nullptr
user-defined-literal: user-defined-integer-literal user-defined-floating-point-literal user-defined-string-literal user-defined-character-literal
user-defined-integer-literal: decimal-literal ud-suffix octal-literal ud-suffix hexadecimal-literal ud-suffix binary-literal ud-suffix
user-defined-floating-point-literal: fractional-constant exponent-part ud-suffix digit-sequence exponent-part ud-suffix hexadecimal-prefix hexadecimal-fractional-constant binary-exponent-part ud-suffix hexadecimal-prefix hexadecimal-digit-sequence binary-exponent-part ud-suffix
user-defined-string-literal: string-literal ud-suffix
user-defined-character-literal: character-literal ud-suffix
ud-suffix: identifier
operator "" X(nULL)
operator "" X("n")
operator "" X<'', '', ... ''>()where n is the source character sequence .
operator "" X(fL)
operator "" X("f")
operator "" X<'', '', ... ''>()where f is the source character sequence .
operator "" X<str>()
operator "" X(str, len)
operator "" X(ch)
long double operator "" _w(long double); std::string operator "" _w(const char16_t*, std::size_t); unsigned operator "" _w(const char*); int main() { 1.2_w; // calls operator "" _w(1.2L) u"one"_w; // calls operator "" _w(u"one", 3) 12_w; // calls operator "" _w("12") "two"_w; // error: no applicable literal operator }— end example
int a; // defines a extern const int c = 1; // defines c int f(int x) { return x+a; } // defines f and defines x struct S { int a; int b; }; // defines S, S::a, and S::b struct X { // defines X int x; // defines non-static data member x static int y; // declares static data member y X(): x(0) { } // defines a constructor of X }; int X::y = 1; // defines X::y enum { up, down }; // defines up and down namespace N { int d; } // defines N and N::d namespace N1 = N; // defines N1 X anX; // defines anXwhereas these are just declarations:
extern int a; // declares a extern const int c; // declares c int f(int); // declares f struct S; // declares S typedef int Int; // declares Int extern X anotherX; // declares anotherX using N::d; // declares d
#include <string> struct C { std::string s; // std::string is the standard library class ([string.classes]) }; int main() { C a; C b = a; b = a; }the implementation will implicitly define functions to make the definition of C equivalent to
struct C { std::string s; C() : s() { } C(const C& x): s(x.s) { } C(C&& x): s(static_cast<std::string&&>(x.s)) { } // : s(std::move(x.s)) { } C& operator=(const C& x) { s = x.s; return *this; } C& operator=(C&& x) { s = static_cast<std::string&&>(x.s); return *this; } // { s = std::move(x.s); return *this; } ~C() { } };
struct S { static const int x = 0; }; const int &f(const int &r); int n = b ? (1, S::x) // S::x is not odr-used here : f(S::x); // S::x is odr-used here, so a definition is required— end example
void f(int n) { [] { n = 1; }; // error: n is not odr-usable due to intervening lambda-expression struct A { void f() { n = 2; } // error: n is not odr-usable due to intervening function definition scope }; void g(int = n); // error: n is not odr-usable due to intervening function parameter scope [=](int k = n) {}; // error: n is not odr-usable due to being // outside the block scope of the lambda-expression [&] { [n]{ return n; }; }; // OK }— end example
auto f() { struct A {}; return A{}; } decltype(f()) g(); auto x = g();
struct X; // declare X as a struct type struct X* x1; // use X in pointer formation X* x2; // use X in pointer formation
// translation unit 1: struct X { X(int, int); X(int, int, int); }; X::X(int, int = 0) { } class D { X x = 0; }; D d1; // X(int, int) called by D() // translation unit 2: struct X { X(int, int); X(int, int, int); }; X::X(int, int = 0, int = 0) { } class D { X x = 0; }; D d2; // X(int, int, int) called by D(); // D()'s implicit definition violates the ODR— end example
inline void f(bool cond, void (*p)()) { if (cond) f(false, []{}); } inline void g(bool cond, void (*p)() = []{}) { if (cond) g(false); } struct X { void h(bool cond, void (*p)() = []{}) { if (cond) h(false); } };
int j = 24; int main() { int i = j, j; j = 42; }the identifier j is declared twice as a name (and used twice).
unsigned char x = 12; { unsigned char x = x; }
class-key attribute-specifier-seq identifier ;the identifier is declared to be a class-name in the scope that contains the declaration, otherwise
class-key identifierif the elaborated-type-specifier is used in the decl-specifier-seq or parameter-declaration-clause of a function defined in namespace scope, the identifier is declared as a class-name in the namespace that contains the declaration; otherwise, except as a friend declaration, the identifier is declared in the smallest namespace or block scope that contains the declaration.
typedef unsigned char T; template<class T = T // lookup finds the typedef name of unsigned char , T // lookup finds the template parameter N = 0> struct A { };— end example
if (int x = f()) { int x; // error: redeclaration of x } else { int x; // error: redeclaration of x }— end example
namespace N { int i; int g(int a) { return a; } int j(); void q(); } namespace { int l=1; } // the potential scope of l is from its point of declaration to the end of the translation unit namespace N { int g(char a) { // overloads N::g(int) return l+a; // l is from unnamed namespace } int i; // error: duplicate definition int j(); // OK: duplicate function declaration int j() { // OK: definition of N::j() return g(i); // calls N::g(int) } int q(); // error: different return type }— end example
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
typedef int c; enum { i = 1 }; class X { char v[i]; // error: i refers to ::i but when reevaluated is X::i int f() { return sizeof(c); } // OK: X::c char c; enum { i = 2 }; }; typedef char* T; struct Y { T a; // error: T refers to ::T but when reevaluated is Y::T typedef long T; T b; }; typedef int I; class D { typedef I I; // error, even though no reordering involved };— end example
namespace N { template<class T> struct A { }; // #1 template<class U> void f(U) { } // #2 struct B { template<class V> friend int g(struct C*); // #3 }; }
template<class T, T* p, class U = T> class X { /* ... */ }; template<class T> void f(T* p = new T);
template<class T> class X : public Array<T> { /* ... */ }; template<class T> class Y : public T { /* ... */ };
int h; void g(); namespace N { struct A {}; template <class T> int f(T); template <class T> int g(T); template <class T> int h(T); } int x = f<N::A>(N::A()); // OK: lookup of f finds nothing, f treated as template name int y = g<N::A>(N::A()); // OK: lookup of g finds a function, g treated as template name int z = h<N::A>(N::A()); // error: h< does not begin a template-id
typedef int f; namespace N { struct A { friend void f(A &); operator int(); void g(A a) { int i = f(a); // f is the typedef, not the friend function: equivalent to int(a) } }; }
namespace A { namespace N { void f(); } } void A::N::f() { i = 5; // The following scopes are searched for a declaration of i: // 1) outermost block scope of A::N::f, before the use of i // 2) scope of namespace N // 3) scope of namespace A // 4) global scope, before the definition of A::N::f }— end example
namespace M { class B { }; }
namespace N { class Y : public M::B { class X { int a[i]; }; }; } // The following scopes are searched for a declaration of i: // 1) scope of class N::Y::X, before the use of i // 2) scope of class N::Y, before the definition of N::Y::X // 3) scope of N::Y's base class M::B // 4) scope of namespace N, before the definition of N::Y // 5) global scope, before the definition of N— end example
class B { }; namespace M { namespace N { class X : public B { void f(); }; } } void M::N::X::f() { i = 16; } // The following scopes are searched for a declaration of i: // 1) outermost block scope of M::N::X::f, before the use of i // 2) scope of class M::N::X // 3) scope of M::N::X's base class B // 4) scope of namespace M::N // 5) scope of namespace M // 6) global scope, before the definition of M::N::X::f— end example
struct A { typedef int AT; void f1(AT); void f2(float); template <class T> void f3(); }; struct B { typedef char AT; typedef float BT; friend void A::f1(AT); // parameter type is A::AT friend void A::f2(BT); // parameter type is B::BT friend void A::f3<AT>(); // template argument is B::AT };— end example
namespace N { int i = 4; extern int j; } int i = 2; int N::j = i; // N::j == 4— end example
namespace N { struct S { }; void f(S); } void g() { N::S s; f(s); // OK: calls N::f (f)(s); // error: N::f not considered; parentheses prevent argument-dependent lookup }— end example
namespace NS { class T { }; void f(T); void g(T, int); } NS::T parm; void g(NS::T, float); int main() { f(parm); // OK: calls NS::f extern void g(NS::T, float); g(parm, 1); // OK: calls g(NS::T, float) }— 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
class A { public: static int n; }; int main() { int A; A::n = 42; // OK A b; // error: A does not name a type }— end example
class X { }; class C { class X { }; static const int number = 50; static X arr[number]; }; X C::arr[number]; // error: // equivalent to ::X C::arr[C::number]; // and not to C::X C::arr[C::number];— end example
nested-name-specifier type-name :: ~ type-namethe second type-name is looked up in the same scope as the first.
struct C { typedef int I; }; typedef int I1, I2; extern int* p; extern int* q; p->C::I::~I(); // I is looked up in the scope of C q->I1::~I2(); // I2 is looked up in the scope of the postfix-expression struct A { ~A(); }; typedef A AB; int main() { AB* p; p->AB::~AB(); // explicitly calls the destructor for A }— end example
struct A { A(); }; struct B: public A { B(); }; A::A() { } B::B() { } B::A ba; // object of type A A::A a; // error: A::A is not a type name struct A::A a2; // object of type A— end example
int x; namespace Y { void f(float); void h(int); } namespace Z { void h(double); } namespace A { using namespace Y; void f(int); void g(int); int i; } namespace B { using namespace Z; void f(char); int i; } namespace AB { using namespace A; using namespace B; void g(); } void h() { AB::g(); // g is declared directly in AB, therefore S is { AB::g() } and AB::g() is chosen AB::f(1); // f is not declared directly in AB so the rules are applied recursively to A and B; // namespace Y is not searched and Y::f(float) is not considered; // S is and overload resolution chooses A::f(int) AB::f('c'); // as above but resolution chooses B::f(char) AB::x++; // x is not declared directly in AB, and is not declared in A or B, so the rules // are applied recursively to Y and Z, S is { } so the program is ill-formed AB::i++; // i is not declared directly in AB so the rules are applied recursively to A and B, // S is so the use is ambiguous and the program is ill-formed AB::h(16.8); // h is not declared directly in AB and not declared directly in A or B so the rules // are applied recursively to Y and Z, S is and // overload resolution chooses Z::h(double) }— end example
namespace A { int a; } namespace B { using namespace A; } namespace C { using namespace A; } namespace BC { using namespace B; using namespace C; } void f() { BC::a++; // OK: S is } namespace D { using A::a; } namespace BD { using namespace B; using namespace D; } void g() { BD::a++; // OK: S is }— end example
namespace B { int b; } namespace A { using namespace B; int a; } namespace B { using namespace A; } void f() { A::a++; // OK: a declared directly in A, S is { A::a } B::a++; // OK: both A and B searched (once), S is { A::a } A::b++; // OK: both A and B searched (once), S is { B::b } B::b++; // OK: b declared directly in B, S is { B::b } }
namespace A { struct x { }; int x; int y; } namespace B { struct y { }; } namespace C { using namespace A; using namespace B; int i = C::x; // OK, A::x (of type int) int j = C::y; // ambiguous, A::y or B::y }— end example
nested-name-specifier unqualified-idthe unqualified-id shall name a member of the namespace designated by the nested-name-specifier or of an element of the inline namespace set of that namespace.
namespace A { namespace B { void f1(int); } using namespace B; } void A::f1(int){ } // error: f1 is not a member of A— end example
namespace A { namespace B { void f1(int); } } namespace C { namespace D { void f1(int); } } using namespace A; using namespace C::D; void B::f1(int){ } // OK, defines A::B::f1(int)— end example
class-key attribute-specifier-seq identifier ;the identifier is looked up according to [basic.lookup.unqual] but ignoring any non-type names that have been declared.
class-key attribute-specifier-seq identifier ;the elaborated-type-specifier is a declaration that introduces the class-name as described in [basic.scope.pdecl].
struct Node { struct Node* Next; // OK: Refers to injected-class-name Node struct Data* Data; // OK: Declares type Data at global scope and member Data }; struct Data { struct Node* Node; // OK: Refers to Node at global scope friend struct ::Glob; // error: Glob is not declared, cannot introduce a qualified type ([dcl.type.elab]) friend struct Glob; // OK: Refers to (as yet) undeclared Glob at global scope. /* ... */ }; struct Base { struct Data; // OK: Declares nested Data struct ::Data* thatData; // OK: Refers to ::Data struct Base::Data* thisData; // OK: Refers to nested Data friend class ::Data; // OK: global Data is a friend friend class Data; // OK: nested Data is a friend struct Data { /* ... */ }; // Defines nested Data }; struct Data; // OK: Redeclares Data at global scope struct ::Data; // error: cannot introduce a qualified type ([dcl.type.elab]) struct Base::Data; // error: cannot introduce a qualified type ([dcl.type.elab]) struct Base::Datum; // error: Datum undefined struct Base::Data* pBase; // OK: refers to nested Data— end example
struct A { }; struct B { struct A { }; void f(::A* a); }; void B::f(::A* a) { a->~A(); // OK: lookup in *a finds the injected-class-name }— end example
class-name-or-namespace-name::...the class-name-or-namespace-name following the . or -> operator is first looked up in the class of the object expression ([class.member.lookup]) and the name, if found, is used.
::class-name-or-namespace-name::...the class-name-or-namespace-name is looked up in global scope as a class-name or namespace-name.
struct A { }; namespace N { struct A { void g() { } template <class T> operator T(); }; } int main() { N::A a; a.operator A(); // calls N::A::operator N::A }— end example
translation-unit: declaration-seq global-module-fragment module-declaration declaration-seq private-module-fragment
static void f(); extern "C" void h(); static int i = 0; // #1 void g() { extern void f(); // internal linkage extern void h(); // C language linkage int i; // #2: i has no linkage { extern void f(); // internal linkage extern int i; // #3: external linkage, ill-formed } }
namespace X { void p() { q(); // error: q not yet declared extern void q(); // q is a member of namespace X } void middle() { q(); // error: q not yet declared } void q() { /* ... */ } // definition of X::q } void q() { /* ... */ } // some other, unrelated q— 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 a specialization might be an exposure
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
template<typename ...T> struct AlignedUnion { alignas(T...) unsigned char data[max(sizeof(T)...)]; }; int f() { AlignedUnion<int, char> au; int *p = new (au.data) int; // OK, au.data provides storage char *c = new (au.data) char(); // OK, ends lifetime of *p char *d = new (au.data + 1) char(); return *c + *d; // OK } struct A { unsigned char a[32]; }; struct B { unsigned char b[16]; }; A a; B *b = new (a.a + 8) B; // a.a provides storage for *b int *p = new (b->b + 4) int; // b->b provides storage for *p // a.a does not provide storage for *p (directly), // but *p is nested within a (see below)— end example
static const char test1 = 'x'; static const char test2 = 'x'; const bool b = &test1 != &test2; // always true— end example
#include <cstdlib> struct X { int a, b; }; X *make_x() { // The call to std::malloc implicitly creates an object of type X // and its subobjects a and b, and returns a pointer to that X object // (or an object that is pointer-interconvertible ([basic.compound]) with it), // in order to give the subsequent class member access operations // defined behavior. X *p = (X*)std::malloc(sizeof(struct X)); p->a = 1; p->b = 2; return p; }— end example
#include <cstdlib> struct B { virtual void f(); void mutate(); virtual ~B(); }; struct D1 : B { void f(); }; struct D2 : B { void f(); }; void B::mutate() { new (this) D2; // reuses storage --- ends the lifetime of *this f(); // undefined behavior ... = this; // OK, this points to valid memory } void g() { void* p = std::malloc(sizeof(D1) + sizeof(D2)); B* pb = new (p) D1; pb->mutate(); *pb; // OK: pb points to valid memory void* q = pb; // OK: pb points to valid memory pb->f(); // undefined behavior: lifetime of *pb has ended }— end example
struct C { int i; void f(); const C& operator=( const C& ); }; const C& C::operator=( const C& other) { if ( this != &other ) { this->~C(); // lifetime of *this ends new (this) C(other); // new object of type C created f(); // well-defined } return *this; } C c1; C c2; c1 = c2; // well-defined c1.f(); // well-defined; c1 refers to a new object of type C— end example
class T { }; struct B { ~B(); }; void h() { B b; new (&b) T; } // undefined behavior at block exit— end example
struct B { B(); ~B(); }; const B b; void h() { b.~B(); new (const_cast<B*>(&b)) const B; // undefined behavior }— end example
int f(bool b) { unsigned char c; unsigned char d = c; // OK, d has an indeterminate value int e = d; // undefined behavior return b ? d : 0; // undefined behavior if b is true }— end example
[[nodiscard]] void* operator new(std::size_t); [[nodiscard]] void* operator new(std::size_t, std::align_val_t); void operator delete(void*) noexcept; void operator delete(void*, std::size_t) noexcept; void operator delete(void*, std::align_val_t) noexcept; void operator delete(void*, std::size_t, std::align_val_t) noexcept; [[nodiscard]] void* operator new[](std::size_t); [[nodiscard]] void* operator new[](std::size_t, std::align_val_t); void operator delete[](void*) noexcept; void operator delete[](void*, std::size_t) noexcept; void operator delete[](void*, std::align_val_t) noexcept; void operator delete[](void*, std::size_t, std::align_val_t) noexcept;
struct B { long double d; }; struct D : virtual B { char c; };
class X { public: X(int); X(const X&); X& operator=(const X&); ~X(); }; class Y { public: Y(int); Y(Y&&); ~Y(); }; X f(X); Y g(Y); void h() { X a(1); X b = f(X(2)); Y c = g(Y(3)); a = f(a); }
template<typename T> using id = T; int i = 1; int&& a = id<int[3]>{1, 2, 3}[i]; // temporary array has same lifetime as a const int& b = static_cast<const int&>(0); // temporary int has same lifetime as b int&& c = cond ? id<int[3]>{1, 2, 3}[i] : static_cast<int&&>(0); // exactly one of the two temporaries is lifetime-extended— end example
const int& x = (const int&)1; // temporary for value 1 has same lifetime as x— end example
struct S { int mi; const std::pair<int,int>& mp; }; S a { 1, {2,3} }; S* p = new S{ 1, {2,3} }; // creates dangling reference— end example
struct S { S(); S(int); friend S operator+(const S&, const S&); ~S(); }; S obj1; const S& cr = S(16)+S(23); S obj2;
constexpr std::size_t N = sizeof(T); char buf[N]; T obj; // obj initialized to its original value std::memcpy(buf, &obj, N); // between these two calls to std::memcpy, obj might be modified std::memcpy(&obj, buf, N); // at this point, each subobject of obj of scalar type holds its original value— end example
T* t1p; T* t2p; // provided that t2p points to an initialized object ... std::memcpy(t1p, t2p, sizeof(T)); // at this point, every subobject of trivially copyable type in *t1p contains // the same value as the corresponding subobject in *t2p— end example
class X; // X is an incomplete type extern X* xp; // xp is a pointer to an incomplete type extern int arr[]; // the type of arr is incomplete typedef int UNKA[]; // UNKA is an incomplete type UNKA* arrp; // arrp is a pointer to an incomplete type UNKA** arrpp; void foo() { xp++; // error: X is incomplete arrp++; // error: incomplete type arrpp++; // OK: sizeof UNKA* is known } struct X { int i; }; // now X is a complete type int arr[10]; // now the type of arr is complete X x; void bar() { xp = &x; // OK; type is “pointer to X” arrp = &arr; // error: different types xp++; // OK: X is complete arrp++; // error: UNKA can't be completed }— end example
Type | Minimum width N |
signed char | 8 |
short | 16 |
int | 16 |
long | 32 |
long long | 64 |
no cv-qualifier | < | const |
no cv-qualifier | < | volatile |
no cv-qualifier | < | const volatile |
const | < | const volatile |
volatile | < | const volatile |