{ expression }indicates an optional expression enclosed in braces.
struct {
char a;
int b:5,
c:11,
:0,
d:8;
struct {int ee:8;} e;
}
struct X { const int n; };
union U { X x; float f; };
void tong() {
U u = {{ 1 }};
u.f = 5.f; // OK, creates new subobject of u ([class.union])
X *p = new (&u.x) X {2}; // OK, creates new subobject of u
assert(p->n == 2); // OK
assert(*std::launder(&u.x.n) == 2); // OK
assert(u.x.n == 2); // undefined behavior, u.x does not name new subobject
}
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)
static const char test1 = 'x';
static const char test2 = 'x';
const bool b = &test1 != &test2; // always true
int a, b;
/* ... */
a = a + 32760 + b + 5;
the expression statement behaves exactly the same as
a = (((a + 32760) + b) + 5);due to the associativity and precedence of these operators.
a = ((a + b) + 32765);since if the values for a and b were, respectively, -32754 and -15, the sum a + b would produce an exception while the original expression would not; nor can the expression be rewritten either as
a = ((a + 32765) + b);or
a = (a + (b + 32765));since the values for a and b might have been, respectively, 4 and -8 or -17 and 12.
struct S {
S(int i): I(i) { } // full-expression is initialization of I
int& v() { return I; }
~S() noexcept(false) { }
private:
int I;
};
S s1(1); // full-expression is call of S::S(int)
void f() {
S s2 = 2; // full-expression is call of S::S(int)
if (S(3).v()) // full-expression includes lvalue-to-rvalue and
// int to bool conversions, performed before
// temporary is deleted at end of full-expression
{ }
bool b = noexcept(S()); // exception specification of destructor of S
// considered for noexcept
// full-expression is destruction of s2 at end of block
}
struct B {
B(S = S(0));
};
B b[2] = { B(), B() }; // full-expression is the entire initialization
// including the destruction of temporaries
void g(int i) {
i = 7, i++, i++; // i becomes 9
i = i++ + 1; // the value of i is incremented
i = i++ + i; // the behavior is undefined
i = i + 1; // the value of i is incremented
}
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-quadThe character designated by the universal-character-name \UNNNNNNNN is that character whose character short name in ISO/IEC 10646 is NNNNNNNN; the character designated by the universal-character-name \uNNNN is that character whose character short name in ISO/IEC 10646 is 0000NNNN.
preprocessing-token: header-name 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
#define R "x"
const char* s = R"y"; // ill-formed raw string, not "x" "y"
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 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 |
alignas | continue | friend | register | true |
alignof | decltype | goto | reinterpret_cast | try |
asm | default | if | return | typedef |
auto | delete | inline | short | typeid |
bool | do | int | signed | typename |
break | double | long | sizeof | union |
case | dynamic_cast | mutable | static | unsigned |
catch | else | namespace | static_assert | using |
char | enum | new | static_cast | virtual |
char16_t | explicit | noexcept | struct | void |
char32_t | export | nullptr | switch | volatile |
class | extern | operator | template | wchar_t |
const | false | private | this | while |
constexpr | float | protected | thread_local | |
const_cast | for | public | throw |
preprocessing-op-or-punc: one of { } [ ] # ## ( ) <: :> <% %> %: %:%: ; : ... new delete ? :: . .* + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || ++ -- , ->* -> and and_eq bitand bitor compl not not_eq or or_eq xor xor_eqEach preprocessing-op-or-punc is converted to a single token in translation phase 7 ([lex.phases]).
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: 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
Suffix | Decimal literal | Binary, octal, or hexadecimal 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 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-literal: decimal-floating-literal hexadecimal-floating-literal
decimal-floating-literal: fractional-constant exponent-part floating-suffix digit-sequence exponent-part floating-suffix
hexadecimal-floating-literal: hexadecimal-prefix hexadecimal-fractional-constant binary-exponent-part floating-suffix hexadecimal-prefix hexadecimal-digit-sequence binary-exponent-part floating-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-suffix: one of f l F 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 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);
boolean-literal: false true
pointer-literal: nullptr
user-defined-literal: user-defined-integer-literal user-defined-floating-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-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<'', '', ... ''>()operator "" X(fL)
operator "" X("f")
operator "" X<'', '', ... ''>()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
}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 (Clause [strings])
};
int main() {
C a;
C b = a;
b = a;
}
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
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
int j = 24;
int main() {
int i = j, j;
j = 42;
}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 { };
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
}
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
};
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 { /* ... */ };
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
}
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
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
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
};
namespace N {
int i = 4;
extern int j;
}
int i = 2;
int N::j = i; // N::j == 4
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
}
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)
}
class A {
public:
static int n;
};
int main() {
int A;
A::n = 42; // OK
A b; // ill-formed: A does not name a type
}
class X { };
class C {
class X { };
static const int number = 50;
static X arr[number];
};
X C::arr[number]; // ill-formed:
// equivalent to ::X C::arr[C::number];
// and not to C::X C::arr[C::number];
nested-name-specifier class-name :: ~ class-namethe second class-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
}
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
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)
}
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
}
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
}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 ([namespace.def]) of that namespace.
namespace A {
namespace B {
void f1(int);
}
using namespace B;
}
void A::f1(int){ } // ill-formed, f1 is not a member of A
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)
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 Node at global scope
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
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
}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 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
}static void f(); static int i = 0; // #1 void g() { extern void f(); // internal 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
template <class T> struct B {
void g(T) { }
void h(T);
friend void i(B, T) { }
};
void f() {
struct A { int x; }; // no linkage
A a = { 1 };
B<A> ba; // declares B<A>::g(A) and B<A>::h(A)
ba.g(a); // OK
ba.h(a); // error: B<A>::h(A) not defined in the translation unit
i(ba, a); // OK
}
inline double fd() { return 1.0; }
extern double d1;
double d2 = d1; // unspecified:
// may be statically initialized to 0.0 or
// dynamically initialized to 0.0 if d1 is
// dynamically initialized, or 1.0 otherwise
double d1 = fd(); // may be initialized statically or dynamically to 1.0
// - File 1 - #include "a.h" #include "b.h" B b; A::A(){ b.Use(); } // - File 2 - #include "a.h" A a; // - File 3 - #include "a.h" #include "b.h" extern A a; extern B b; int main() { a.Use(); b.Use(); }
void* operator new(std::size_t); 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; void* operator new[](std::size_t); 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;
#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
}
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
class T { };
struct B {
~B();
};
void h() {
B b;
new (&b) T;
} // undefined behavior at block exit
struct B {
B();
~B();
};
const B b;
void h() {
b.~B();
new (const_cast<B*>(&b)) const B; // undefined behavior
}#define 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
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
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++; // ill-formed: X is incomplete arrp++; // ill-formed: 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; // ill-formed: different types xp++; // OK: X is complete arrp++; // ill-formed: UNKA can't be completed }
no cv-qualifier | < | const |
no cv-qualifier | < | volatile |
no cv-qualifier | < | const volatile |
const | < | const volatile |
volatile | < | const volatile |
struct B { long double d; };
struct D : virtual B { char c; };
struct S { int n; };
auto f() {
S x { 1 };
constexpr S y { 2 };
return [&](bool b) { return (b ? y : x).n; };
}
auto g = f();
int m = g(false); // undefined behavior due to access of x.n outside its lifetime
int n = g(true); // OK, does not access y.n
struct X { int n; };
int k = X().n; // OK, X() prvalue is converted to xvalue
int main() {
const char c = 'c';
char* pc;
const char** pcc = &pc; // #1: not allowed
*pcc = &c;
*pc = 'C'; // #2: modifies a const object
}void (*p)(); void (**pp)() noexcept = &p; // error: cannot convert to pointer to noexcept function struct S { typedef void (*p)(); operator p(); }; void (*q)() noexcept = S(); // error: cannot convert to pointer to noexcept function
struct A {
char g();
template<class T> auto f(T t) -> decltype(t + g())
{ return t + g(); }
};
template auto A::f(int t) -> decltype(t + g());
class Outer {
int a[sizeof(*this)]; // error: not inside a member function
unsigned int sz = sizeof(*this); // OK: in default member initializer
void f() {
int b[sizeof(*this)]; // OK
struct Inner {
int c[sizeof(*this)]; // error: not inside a member function of Inner
};
}
};
struct S {
int m;
};
int i = sizeof(S::m); // OK
int j = sizeof(S::m + 42); // OK
unqualified-id: identifier operator-function-id conversion-function-id literal-operator-id ~ class-name ~ decltype-specifier template-id
qualified-id: nested-name-specifier template unqualified-id
nested-name-specifier: :: type-name :: namespace-name :: decltype-specifier :: nested-name-specifier identifier :: nested-name-specifier template simple-template-id ::
lambda-expression: lambda-introducer lambda-declarator compound-statement
lambda-introducer: [ lambda-capture ]
lambda-declarator: ( parameter-declaration-clause ) decl-specifier-seq noexcept-specifier attribute-specifier-seq trailing-return-type
#include <algorithm>
#include <cmath>
void abssort(float* x, unsigned N) {
std::sort(x, x + N, [](float a, float b) { return std::abs(a) < std::abs(b); });
}
auto x1 = [](int i){ return i; }; // OK: return type is int
auto x2 = []{ return { 1, 2 }; }; // error: deducing return type from braced-init-list
int j;
auto x3 = []()->auto&& { return j; }; // OK: return type is int&
auto glambda = [](auto a, auto&& b) { return a < b; };
bool b = glambda(3, 3.14); // OK
auto vglambda = [](auto printer) {
return [=](auto&& ... ts) { // OK: ts is a function parameter pack
printer(std::forward<decltype(ts)>(ts)...);
return [=]() {
printer(ts ...);
};
};
};
auto p = vglambda( [](auto v1, auto v2, auto v3)
{ std::cout << v1 << v2 << v3; } );
auto q = p(1, 'a', 3.14); // OK: outputs 1a3.14
q(); // OK: outputs 1a3.14
auto ID = [](auto a) { return a; };
static_assert(ID(3) == 3); // OK
struct NonLiteral {
NonLiteral(int n) : n(n) { }
int n;
};
static_assert(ID(NonLiteral{3}).n == 3); // ill-formed
auto monoid = [](auto v) { return [=] { return v; }; };
auto add = [](auto m1) constexpr {
auto ret = m1();
return [=](auto m2) mutable {
auto m1val = m1();
auto plus = [=](auto m2val) mutable constexpr
{ return m1val += m2val; };
ret = plus(m2());
return monoid(ret);
};
};
constexpr auto zero = monoid(0);
constexpr auto one = monoid(1);
static_assert(add(one)(zero)() == one()); // OK
// Since two below is not declared constexpr, an evaluation of its constexpr member function call operator
// cannot perform an lvalue-to-rvalue conversion on one of its subobjects (that represents its capture)
// in a constant expression.
auto two = monoid(2);
assert(two() == 2); // OK, not a constant expression.
static_assert(add(one)(one)() == two()); // ill-formed: two() is not a constant expression
static_assert(add(one)(one)() == monoid(2)()); // OK
auto glambda = [](auto a) { return a; };
int (*fp)(int) = glambda;
The behavior of the conversion function of glambda above is like
that of the following conversion function:
struct Closure {
template<class T> auto operator()(T t) const { ... }
template<class T> static auto lambda_call_operator_invoker(T a) {
// forwards execution to operator()(a) and therefore has
// the same return type deduced
...
}
template<class T> using fptr_t =
decltype(lambda_call_operator_invoker(declval<T>())) (*)(T);
template<class T> operator fptr_t<T>() const
{ return &lambda_call_operator_invoker; }
};
void f1(int (*)(int)) { }
void f2(char (*)(int)) { }
void g(int (*)(int)) { } // #1
void g(char (*)(char)) { } // #2
void h(int (*)(int)) { } // #3
void h(char (*)(int)) { } // #4
auto glambda = [](auto a) { return a; };
f1(glambda); // OK
f2(glambda); // error: ID is not convertible
g(glambda); // error: ambiguous
h(glambda); // OK: calls #3 since it is convertible from ID
int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
auto GL = [](auto a) { std::cout << a; return a; };
int (*GL_int)(int) = GL; // OK: through conversion function template
GL_int(3); // OK: same as GL(3)
auto Fwd = [](int (*fp)(int), auto a) { return fp(a); };
auto C = [](auto a) { return a; };
static_assert(Fwd(C,3) == 3); // OK
// No specialization of the function call operator template can be constexpr (due to the local static).
auto NC = [](auto a) { static int s; return a; };
static_assert(Fwd(NC,3) == 3); // ill-formed
struct S1 {
int x, y;
int operator()(int);
void f() {
[=]()->int {
return operator()(this->x + y); // equivalent to S1::operator()(this->x + (*this).y)
// this has type S1*
};
}
};lambda-capture: capture-default capture-list capture-default , capture-list
capture-default: & =
capture-list: capture ... capture-list , capture ...
capture: simple-capture init-capture
simple-capture: identifier & identifier this * this
init-capture: identifier initializer & identifier initializer
struct S2 { void f(int i); };
void S2::f(int i) {
[&, i]{ }; // OK
[&, &i]{ }; // error: i preceded by & when & is the default
[=, *this]{ }; // OK
[=, this]{ }; // error: this when = is the default
[i, i]{ }; // error: i repeated
[this, *this]{ }; // error: this appears twice
}
void f() {
int x = 0;
auto g = [x](int x) { return 0; } // error: parameter and simple-capture have the same name
}
int x = 4;
auto y = [&r = x, x = x+1]()->int {
r += 2;
return x+2;
}(); // Updates ::x to 6, and initializes y to 7.
auto z = [a = 42](int a) { return 1; } // error: parameter and local variable have the same name
void f(int, const int (&)[2] = {}) { } // #1
void f(const int&, const int (&)[1]) { } // #2
void test() {
const int x = 17;
auto g = [](auto a) {
f(x); // OK: calls #1, does not capture x
};
auto g2 = [=](auto a) {
int selector[sizeof(a) == 1 ? 1 : 2]{};
f(x, selector); // OK: is a dependent expression, so captures x
};
}
void f1(int i) {
int const N = 20;
auto m1 = [=]{
int const M = 30;
auto m2 = [i]{
int x[N][M]; // OK: N and M are not odr-used
x[0][0] = i; // OK: i is explicitly captured by m2 and implicitly captured by m1
};
};
struct s1 {
int f;
void work(int n) {
int m = n*n;
int j = 40;
auto m3 = [this,m] {
auto m4 = [&,j] { // error: j not captured by m3
int x = n; // error: n implicitly captured by m4 but not captured by m3
x += m; // OK: m implicitly captured by m4 and explicitly captured by m3
x += i; // error: i is outside of the reaching scope
x += f; // OK: this captured implicitly by m4 and explicitly by m3
};
};
}
};
}
struct s2 {
double ohseven = .007;
auto f() {
return [this] {
return [*this] {
return ohseven; // OK
}
}();
}
auto g() {
return [] {
return [*this] { }; // error: *this not captured by outer lambda-expression
}();
}
};
void f2() {
int i = 1;
void g1(int = ([i]{ return i; })()); // ill-formed
void g2(int = ([i]{ return 0; })()); // ill-formed
void g3(int = ([=]{ return i; })()); // ill-formed
void g4(int = ([=]{ return 0; })()); // OK
void g5(int = ([]{ return sizeof i; })()); // OK
}
void f(const int*);
void g() {
const int N = 10;
[=] {
int arr[N]; // OK: not an odr-use, refers to automatic variable
f(&N); // OK: causes N to be captured; &N points to
// the corresponding member of the closure type
};
}
auto h(int &r) {
return [&] {
++r; // Valid after h returns if the lifetime of the
// object to which r is bound has not ended
};
}
// The inner closure type must be a literal type regardless of how reference captures are represented.
static_assert([](int n) { return [&n] { return ++n; }(); }(3) == 4);
int a = 1, b = 1, c = 1;
auto m1 = [a, &b, &c]() mutable {
auto m2 = [a, b, &c]() mutable {
std::cout << a << b << c;
a = 4; b = 4; c = 4;
};
a = 3; b = 3; c = 3;
m2();
};
a = 2; b = 2; c = 2;
m1();
std::cout << a << b << c;
void f3() {
float x, &r = x;
[=] { // x and r are not captured (appearance in a decltype operand is not an odr-use)
decltype(x) y1; // y1 has type float
decltype((x)) y2 = y1; // y2 has type float const& because this lambda is not mutable and x is an lvalue
decltype(r) r1 = y1; // r1 has type float& (transformation not considered)
decltype((r)) r2 = y2; // r2 has type float const&
};
}
template<class... Args>
void f(Args... args) {
auto lm = [&, args...] { return g(args...); };
lm();
}fold-expression: ( cast-expression fold-operator ... ) ( ... fold-operator cast-expression ) ( cast-expression fold-operator ... fold-operator cast-expression )
fold-operator: one of + - * / % ^ & | << >> += -= *= /= %= ^= &= |= <<= >>= = == != < > <= >= && || , .* ->*
template<typename ...Args>
bool f(Args ...args) {
return (true && ... && args); // OK
}
template<typename ...Args>
bool f(Args ...args) {
return (args + ... + args); // error: both operands contain unexpanded parameter packs
}postfix-expression: primary-expression postfix-expression [ expr-or-braced-init-list ] postfix-expression ( expression-list ) simple-type-specifier ( expression-list ) typename-specifier ( expression-list ) simple-type-specifier braced-init-list typename-specifier braced-init-list postfix-expression . template id-expression postfix-expression -> template id-expression postfix-expression . pseudo-destructor-name postfix-expression -> pseudo-destructor-name postfix-expression ++ postfix-expression -- dynamic_cast < type-id > ( expression ) static_cast < type-id > ( expression ) reinterpret_cast < type-id > ( expression ) const_cast < type-id > ( expression ) typeid ( expression ) typeid ( type-id )
expression-list: initializer-list
pseudo-destructor-name: nested-name-specifier type-name :: ~ type-name nested-name-specifier template simple-template-id :: ~ type-name ~ type-name ~ decltype-specifier
void f() {
std::string s = "but I have heard it works even if you don't believe in it";
s.replace(0, 4, "").replace(s.find("even"), 4, "only").replace(s.find(" don't"), 6, "");
assert(s == "I have heard it works only if you believe in it"); // OK
}
struct S {
S(int);
};
int operator<<(S, int);
int i, j;
int x = S(i=1) << (i=2);
int y = operator<<(S(j=1), j=2);nested-name-specifier type-name :: ~ type-nameshall designate the same scalar type (ignoring cv-qualification).
struct B { };
struct D : B { };
void foo(D* dp) {
B* bp = dynamic_cast<B*>(dp); // equivalent to B* bp = dp;
}
class A { virtual void f(); };
class B { virtual void g(); };
class D : public virtual A, private B { };
void g() {
D d;
B* bp = (B*)&d; // cast needed to break protection
A* ap = &d; // public derivation, no cast needed
D& dr = dynamic_cast<D&>(*bp); // fails
ap = dynamic_cast<A*>(bp); // fails
bp = dynamic_cast<B*>(ap); // fails
ap = dynamic_cast<A*>(&d); // succeeds
bp = dynamic_cast<B*>(&d); // ill-formed (not a runtime check)
}
class E : public D, public B { };
class F : public E, public D { };
void h() {
F f;
A* ap = &f; // succeeds: finds unique A
D* dp = dynamic_cast<D*>(ap); // fails: yields null; f has two D subobjects
E* ep = (E*)ap; // ill-formed: cast from virtual base
E* ep1 = dynamic_cast<E*>(ap); // succeeds
}
class D { /* ... */ };
D d1;
const D d2;
typeid(d1) == typeid(d2); // yields true
typeid(D) == typeid(const D); // yields true
typeid(D) == typeid(d2); // yields true
typeid(D) == typeid(const D&); // yields true
struct B { };
struct D : public B { };
D d;
B &br = d;
static_cast<D&>(br); // produces lvalue to the original d object
T t(e);for some invented temporary variable t ([dcl.init]) and then using the temporary variable as the result of the conversion.
struct B { };
struct D : private B { };
void f() {
static_cast<D*>((B*)0); // error: B is a private base of D
static_cast<int B::*>((int D::*)0); // error: B is a private base of D
}
T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));
bool b = p1 == p2; // b will have the value true.
typedef int *A[3]; // array of 3 pointer to int typedef const int *const CA[3]; // array of 3 const pointer to const int CA &&r = A{}; // OK, reference binds to temporary array object after qualification conversion to type CA A &&r1 = const_cast<A>(CA{}); // error: temporary array decayed to pointer A &&r2 = const_cast<A&&>(CA{}); // OK
unary-expression: postfix-expression ++ cast-expression -- cast-expression unary-operator cast-expression sizeof unary-expression sizeof ( type-id ) sizeof ... ( identifier ) alignof ( type-id ) noexcept-expression new-expression delete-expression
unary-operator: one of * & + - ! ~
struct A { int i; };
struct B : A { };
... &B::i ... // has type int A::*
int a;
int* p1 = &a;
int* p2 = p1 + 1; // defined behavior
bool b = p2 > p1; // defined behavior, with value true
template<class... Types>
struct count {
static const std::size_t value = sizeof...(Types);
};new-expression: :: new new-placement new-type-id new-initializer :: new new-placement ( type-id ) new-initializer
new-placement: ( expression-list )
new-type-id: type-specifier-seq new-declarator
new-declarator: ptr-operator new-declarator noptr-new-declarator
noptr-new-declarator: [ expression ] attribute-specifier-seq noptr-new-declarator [ constant-expression ] attribute-specifier-seq
new-initializer: ( expression-list ) braced-init-listEntities created by a new-expression have dynamic storage duration ([basic.stc.dynamic]).
T x init ;new auto(1); // allocated type is int auto x = new auto('a'); // allocated type is char, x is of type char* template<class T> struct A { A(T, T); }; auto y = new A{1, 2}; // allocated type is A<int>
new int(*[10])(); // error
(new int) (*[10])(); // error
Instead, the explicitly parenthesized version of the new
operator can be used to create objects of compound
types ([basic.compound]):new (int (*[10])());
void mergeable(int x) {
// These allocations are safe for merging:
std::unique_ptr<char[]> a{new (std::nothrow) char[8]};
std::unique_ptr<char[]> b{new (std::nothrow) char[8]};
std::unique_ptr<char[]> c{new (std::nothrow) char[x]};
g(a.get(), b.get(), c.get());
}
void unmergeable(int x) {
std::unique_ptr<char[]> a{new char[8]};
try {
// Merging this allocation would change its catch handler.
std::unique_ptr<char[]> b{new char[x]};
} catch (const std::bad_alloc& e) {
std::cerr << "Allocation failed: " << e.what() << std::endl;
throw;
}
}operator new(sizeof(T)) operator new(sizeof(T), std::align_val_t(alignof(T)))
operator new(sizeof(T), 2, f) operator new(sizeof(T), std::align_val_t(alignof(T)), 2, f)
operator new[](sizeof(T) * 5 + x) operator new[](sizeof(T) * 5 + x, std::align_val_t(alignof(T)))
operator new[](sizeof(T) * 5 + x, 2, f) operator new[](sizeof(T) * 5 + x, std::align_val_t(alignof(T)), 2, f)
struct S {
// Placement allocation function:
static void* operator new(std::size_t, std::size_t);
// Usual (non-placement) deallocation function:
static void operator delete(void*, std::size_t);
};
S* p = new (0) S; // ill-formed: non-placement deallocation function matches
// placement allocation function
delete-expression: :: delete cast-expression :: delete [ ] cast-expressionThe first alternative is for non-array objects, and the second is for arrays.
noexcept-expression: noexcept ( expression )
struct A { };
struct I1 : A { };
struct I2 : A { };
struct D : I1, I2 { };
A* foo( D* p ) {
return (A*)( p ); // ill-formed static_cast interpretation
}
struct S {
S() : i(0) { }
mutable int i;
};
void f()
{
const S cs;
int S::* pm = &S::i; // pm refers to mutable member S::i
cs.*pm = 88; // ill-formed: cs is a const object
}additive-expression: multiplicative-expression additive-expression + multiplicative-expression additive-expression - multiplicative-expressionFor addition, either both operands shall have arithmetic or unscoped enumeration type, or one operand shall be a pointer to a completely-defined object type and the other shall have integral or unscoped enumeration type.
shift-expression: additive-expression shift-expression << additive-expression shift-expression >> additive-expressionThe operands shall be of integral or unscoped enumeration type and integral promotions are performed.
relational-expression: shift-expression relational-expression < shift-expression relational-expression > shift-expression relational-expression <= shift-expression relational-expression >= shift-expressionThe operands shall have arithmetic, enumeration, or pointer type.
equality-expression: relational-expression equality-expression == relational-expression equality-expression != relational-expression
struct A {};
struct B : A { int x; };
struct C : A { int x; };
int A::*bx = (int(A::*))&B::x;
int A::*cx = (int(A::*))&C::x;
bool b1 = (bx == cx); // unspecified
struct B {
int f();
};
struct L : B { };
struct R : B { };
struct D : L, R { };
int (B::*pb)() = &B::f;
int (L::*pl)() = pb;
int (R::*pr)() = pb;
int (D::*pdl)() = pl;
int (D::*pdr)() = pr;
bool x = (pdl == pdr); // false
bool y = (pb == pl); // true
conditional-expression: logical-or-expression logical-or-expression ? expression : assignment-expression
try {
// ...
} catch (...) { // catch all exceptions
// respond (partially) to exception
throw; // pass the exception to some other handler
}assignment-expression: conditional-expression logical-or-expression assignment-operator initializer-clause throw-expression
assignment-operator: one of = *= /= %= += -= >>= <<= &= ^= |=
complex<double> z;
z = { 1,2 }; // meaning z.operator=({1,2})
z += { 1, 2 }; // meaning z.operator+=({1,2})
int a, b;
a = b = { 1 }; // meaning a=b=1;
a = { 1 } = b; // syntax error
expression: assignment-expression expression , assignment-expressionA pair of expressions separated by a comma is evaluated left-to-right; the left expression is a discarded-value expression (Clause [expr]).
void g() {
const int n = 0;
[=] {
constexpr int i = n; // OK, n is not odr-used and not captured here
constexpr int j = *&n; // ill-formed, &n would be an odr-use of n
};
}
auto monad = [](auto v) { return [=] { return v; }; };
auto bind = [](auto m) {
return [=](auto fvm) { return fvm(m()); };
};
// OK to have captures to automatic objects created during constant expression evaluation.
static_assert(bind(monad(2))(monad)() == monad(2)());int x; // not constant struct A { constexpr A(bool b) : m(b?42:x) { } int m; }; constexpr int v = A(true).m; // OK: constructor call initializes m with the value 42 constexpr int w = A(false).m; // error: initializer for m is x, which is non-constant constexpr int f1(int k) { constexpr int x = k; // error: x is not initialized by a constant expression // because lifetime of k began outside the initializer of x return x; } constexpr int f2(int k) { int x = k; // OK: not required to be a constant expression // because x is not constexpr return x; } constexpr int incr(int &n) { return ++n; } constexpr int g(int k) { constexpr int x = incr(k); // error: incr(k) is not a core constant expression // because lifetime of k began outside the expression incr(k) return x; } constexpr int h(int k) { int x = incr(k); // OK: incr(k) is not required to be a core constant expression return x; } constexpr int y = h(1); // OK: initializes y with the value 2 // h(1) is a core constant expression because // the lifetime of k begins inside h(1)
struct A {
constexpr A(int i) : val(i) { }
constexpr operator int() const { return val; }
constexpr operator long() const { return 43; }
private:
int val;
};
template<int> struct X { };
constexpr A a = 42;
X<a> x; // OK: unique conversion to int
int ary[a]; // error: ambiguous conversion
statement: labeled-statement attribute-specifier-seq expression-statement attribute-specifier-seq compound-statement attribute-specifier-seq selection-statement attribute-specifier-seq iteration-statement attribute-specifier-seq jump-statement declaration-statement attribute-specifier-seq try-block init-statement: expression-statement simple-declaration condition: expression attribute-specifier-seq decl-specifier-seq declarator brace-or-equal-initializerThe optional attribute-specifier-seq appertains to the respective statement.
if (int x = f()) {
int x; // ill-formed, redeclaration of x
}
else {
int x; // ill-formed, redeclaration of x
}labeled-statement: attribute-specifier-seq identifier : statement attribute-specifier-seq case constant-expression : statement attribute-specifier-seq default : statementThe optional attribute-specifier-seq appertains to the label.
compound-statement: { statement-seq }
statement-seq: statement statement-seq statementA compound statement defines a block scope ([basic.scope]).
selection-statement: if constexpr ( init-statement condition ) statement if constexpr ( init-statement condition ) statement else statement switch ( init-statement condition ) statementSee [dcl.meaning] for the optional attribute-specifier-seq in a condition.
template<typename T, typename ... Rest> void g(T&& p, Rest&& ...rs) {
// ... handle p
if constexpr (sizeof...(rs) > 0)
g(rs...); // never instantiated with an empty argument list
}
extern int x; // no definition of x required
int f() {
if constexpr (true)
return 0;
else if (x)
return x;
else
return -x;
}if constexpr ( init-statement condition ) statementis equivalent to
{ init-statement if constexpr ( condition ) statement }and an if statement of the form
if constexpr ( init-statement condition ) statement else statementis equivalent to
{ init-statement if constexpr ( condition ) statement else statement }except that names declared in the init-statement are in the same declarative region as those declared in the condition.
case constant-expression :where the constant-expression shall be a converted constant expression ([expr.const]) of the adjusted type of the switch condition.
switch ( init-statement condition ) statementis equivalent to
{ init-statement switch ( condition ) statement }except that names declared in the init-statement are in the same declarative region as those declared in the condition.
iteration-statement: while ( condition ) statement do statement while ( expression ) ; for ( init-statement condition ; expression ) statement for ( for-range-declaration : for-range-initializer ) statement
for-range-declaration: attribute-specifier-seq decl-specifier-seq declarator attribute-specifier-seq decl-specifier-seq ref-qualifier [ identifier-list ]
for-range-initializer: expr-or-braced-init-listSee [dcl.meaning] for the optional attribute-specifier-seq in a for-range-declaration.
void f() {
for (int i = 0; i < 10; ++i)
int i = 0; // error: redeclaration
for (int i : { 1, 2, 3 })
int i = 1; // error: redeclaration
}
while (T t = x) statement
label:
{ // start of condition scope
T t = x;
if (t) {
statement
goto label;
}
} // end of condition scope
The variable created in a condition is destroyed and created with each
iteration of the loop.
struct A {
int val;
A(int i) : val(i) { }
~A() { }
operator bool() { return val != 0; }
};
int i = 1;
while (A a = i) {
// ...
i = 0;
}for ( init-statement condition ; expression ) statementis equivalent to
{ init-statement while ( condition ) { statement expression ; } }except that names declared in the init-statement are in the same declarative region as those declared in the condition, and except that a continue in statement (not enclosed in another iteration statement) will execute expression before re-evaluating condition.
int i = 42;
int a[10];
for (int i = 0; i < 10; i++)
a[i] = i;
int j = i; // j = 42
for ( for-range-declaration : for-range-initializer ) statementis equivalent to
{ auto &&__range = for-range-initializer ; auto __begin = begin-expr ; auto __end = end-expr ; for ( ; __begin != __end; ++__begin ) { for-range-declaration = *__begin; statement } }where
while (foo) {
{
// ...
}
contin: ;
}
do {
{
// ...
}
contin: ;
} while (foo);
for (;;) {
{
// ...
}
contin: ;
}declaration-statement: block-declarationIf an identifier introduced by a declaration was previously declared in an outer block, the outer declaration is hidden for the remainder of the block, after which it resumes its force.
void f() {
// ...
goto lx; // ill-formed: jump into scope of a
// ...
ly:
X a = 1;
// ...
lx:
goto ly; // OK, jump implies destructor call for a followed by
// construction again immediately following label ly
}
int foo(int i) {
static int s = foo(2*i); // recursive call - undefined
return i+1;
}T(a)->m = 7; // expression-statement T(a)++; // expression-statement T(a,5)<<c; // expression-statement T(*d)(int); // declaration T(e)[5]; // declaration T(f) = { 1, 2 }; // declaration T(*g)(double(3)); // declaration
class T {
// ...
public:
T();
T(int);
T(int, int);
};
T(a); // declaration
T(*b)(); // declaration
T(c)=7; // declaration
T(d),e,f=3; // declaration
extern int h;
T(g)(h,2); // declaration
struct T1 {
T1 operator()(int x) { return T1(x); }
int operator=(int x) { return x; }
T1(int) { }
};
struct T2 { T2(int){ } };
int a, (*(*b)(T2))(int), c, d;
void f() {
// disambiguation requires this to be parsed as a declaration:
T1(a) = 3,
T2(4), // T2 will be declared as a variable of type T1, but this will not
(*(*b)(T2(c)))(int(d)); // allow the last part of the declaration to parse properly,
// since it depends on T2 being a type-name
}declaration-seq: declaration declaration-seq declaration
declaration: block-declaration nodeclspec-function-declaration function-definition template-declaration deduction-guide explicit-instantiation explicit-specialization linkage-specification namespace-definition empty-declaration attribute-declaration
block-declaration: simple-declaration asm-definition namespace-alias-definition using-declaration using-directive static_assert-declaration alias-declaration opaque-enum-declaration
nodeclspec-function-declaration: attribute-specifier-seq declarator ;
alias-declaration: using identifier attribute-specifier-seq = defining-type-id ;
simple-declaration: decl-specifier-seq init-declarator-list ; attribute-specifier-seq decl-specifier-seq init-declarator-list ; attribute-specifier-seq decl-specifier-seq ref-qualifier [ identifier-list ] initializer ;
static_assert-declaration: static_assert ( constant-expression ) ; static_assert ( constant-expression , string-literal ) ;
empty-declaration: ;
attribute-declaration: attribute-specifier-seq ;
attribute-specifier-seq decl-specifier-seq init-declarator-list ;is divided into three parts.
static_assert(char(-1) < 0, "this library requires plain 'char' to be signed");
decl-specifier: storage-class-specifier defining-type-specifier function-specifier friend typedef constexpr inline
decl-specifier-seq: decl-specifier attribute-specifier-seq decl-specifier decl-specifier-seqThe optional attribute-specifier-seq in a decl-specifier-seq appertains to the type determined by the preceding decl-specifiers ([dcl.meaning]).
typedef char* Pc;
static Pc; // error: name missing
void f(const Pc); // void f(char* const) (not const char*) void g(const int Pc); // void g(const int)
storage-class-specifier: static thread_local extern mutableAt most one storage-class-specifier shall appear in a given decl-specifier-seq, except that thread_local may appear with static or extern.
static char* f(); // f() has internal linkage char* f() // f() still has internal linkage { /* ... */ } char* g(); // g() has external linkage static char* g() // error: inconsistent linkage { /* ... */ } void h(); inline void h(); // external linkage inline void l(); void l(); // external linkage inline void m(); extern void m(); // external linkage static void n(); inline void n(); // internal linkage static int a; // a has internal linkage int a; // error: two definitions static int b; // b has internal linkage extern int b; // b still has internal linkage int c; // c has external linkage static int c; // error: inconsistent linkage extern int d; // d has external linkage static int d; // error: inconsistent linkage
struct S;
extern S a;
extern S f();
extern void g(S);
void h() {
g(a); // error: S is incomplete
f(); // error: S is incomplete
}
class X {
mutable const int* p; // OK
mutable int* const q; // ill-formed
};function-specifier: virtual explicit
using handler_t = void (*)(int); extern handler_t ignore; extern void (*ignore)(int); // redeclare ignore using cell = pair<void*, cell*>; // ill-formed
typedef struct s { /* ... */ } s;
typedef int I;
typedef int I;
typedef I I;
struct S {
typedef struct A { } A; // OK
typedef struct B B; // OK
typedef A A; // error
};
struct S;
typedef struct S S;
int main() {
struct S* p; // OK
}
struct S { }; // OK
struct S {
S();
~S();
};
typedef struct S T;
S a = T(); // OK
struct T * p; // error
constexpr void square(int &x); // OK: declaration constexpr int bufsz = 1024; // OK: definition constexpr struct pixel { // error: pixel is a type int x; int y; constexpr pixel(int); // OK: declaration }; constexpr pixel::pixel(int a) : x(a), y(x) // OK: definition { square(x); } constexpr pixel small(2); // error: square not defined, so small(2) // not constant ([expr.const]) so constexpr not satisfied constexpr void square(int &x) { // OK: definition x *= x; } constexpr pixel large(4); // OK: square defined int next(constexpr int x) { // error: not for parameters return x + 1; } extern constexpr int memsz; // error: not a definition
constexpr int square(int x)
{ return x * x; } // OK
constexpr long long_max()
{ return 2147483647; } // OK
constexpr int abs(int x) {
if (x < 0)
x = -x;
return x; // OK
}
constexpr int first(int n) {
static int value = n; // error: variable has static storage duration
return value;
}
constexpr int uninit() {
int a; // error: variable is uninitialized
return a;
}
constexpr int prev(int x)
{ return --x; } // OK
constexpr int g(int x, int n) { // OK
int r = 1;
while (--n > 0) r *= x;
return r;
}
struct Length {
constexpr explicit Length(int i = 0) : val(i) { }
private:
int val;
};
constexpr int f(bool b)
{ return b ? throw 0 : 0; } // OK
constexpr int f() { return f(true); } // ill-formed, no diagnostic required
struct B {
constexpr B(int x) : i(0) { } // x is unused
int i;
};
int global;
struct D : B {
constexpr D() : B(global) { } // ill-formed, no diagnostic required
// lvalue-to-rvalue conversion on non-constant global
};constexpr int bar(int x, int y) // OK { return x + y + x*y; } // ... int bar(int x, int y) // error: redefinition of bar { return x * 2 + 3 * y; }
struct pixel {
int x, y;
};
constexpr pixel ur = { 1294, 1024 }; // OK
constexpr pixel origin; // error: initializer missing
type-specifier: simple-type-specifier elaborated-type-specifier typename-specifier cv-qualifier
type-specifier-seq: type-specifier attribute-specifier-seq type-specifier type-specifier-seq
defining-type-specifier: type-specifier class-specifier enum-specifier
defining-type-specifier-seq: defining-type-specifier attribute-specifier-seq defining-type-specifier defining-type-specifier-seqThe optional attribute-specifier-seq in a type-specifier-seq or a defining-type-specifier-seq appertains to the type denoted by the preceding type-specifiers or defining-type-specifiers ([dcl.meaning]).
const int ci = 3; // cv-qualified (initialized as required) ci = 4; // ill-formed: attempt to modify const int i = 2; // not cv-qualified const int* cip; // pointer to const int cip = &i; // OK: cv-qualified access path to unqualified *cip = 4; // ill-formed: attempt to modify through ptr to const int* ip; ip = const_cast<int*>(cip); // cast needed to convert const int* to int* *ip = 4; // defined: *ip points to i, a non-const object const int* ciq = new const int (3); // initialized as required int* iq = const_cast<int*>(ciq); // cast required *iq = 4; // undefined: modifies a const object
struct X {
mutable int i;
int j;
};
struct Y {
X x;
Y();
};
const Y y;
y.x.i++; // well-formed: mutable member can be modified
y.x.j++; // ill-formed: const-qualified member modified
Y* p = const_cast<Y*>(&y); // cast away const-ness of y
p->x.i = 99; // well-formed: mutable member can be modified
p->x.j = 99; // undefined: modifies a const member
simple-type-specifier: nested-name-specifier type-name nested-name-specifier template simple-template-id nested-name-specifier template-name char char16_t char32_t wchar_t bool short int long signed unsigned float double void auto decltype-specifier
type-name: class-name enum-name typedef-name simple-template-id
decltype-specifier: decltype ( expression ) decltype ( auto )
Specifier(s) | Type |
type-name | the type named |
simple-template-id | the type as defined in [temp.names] |
template-name | placeholder for a type to be deduced |
char | “char” |
unsigned char | “unsigned char” |
signed char | “signed char” |
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” |
auto | placeholder for a type to be deduced |
decltype(auto) | placeholder for a type to be deduced |
decltype(expression) | the type as defined below |
const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1 = 17; // type is const int&&
decltype(i) x2; // type is int
decltype(a->x) x3; // type is double
decltype((a->x)) x4 = x3; // type is const double&
template<class T> struct A { ~A() = delete; };
template<class T> auto h()
-> A<T>;
template<class T> auto i(T) // identity
-> T;
template<class T> auto f(T) // #1
-> decltype(i(h<T>())); // forces completion of A<T> and implicitly uses A<T>::~A()
// for the temporary introduced by the use of h().
// (A temporary is not introduced as a result of the use of i().)
template<class T> auto f(T) // #2
-> void;
auto g() -> void {
f(42); // OK: calls #2. (#1 is not a viable candidate: type deduction
// fails ([temp.deduct]) because A<int>::~A() is implicitly used in its
// decltype-specifier)
}
template<class T> auto q(T)
-> decltype((h<T>())); // does not force completion of A<T>; A<T>::~A() is not implicitly
// used within the context of this decltype-specifier
void r() {
q(42); // Error: deduction against q succeeds, so overload resolution selects
// the specialization “q(T) -> decltype((h<T>())) [with T=int]”.
// The return type is A<int>, so a temporary is introduced and its
// destructor is used, so the program is ill-formed.
}elaborated-type-specifier: class-key attribute-specifier-seq nested-name-specifier identifier class-key simple-template-id class-key nested-name-specifier template simple-template-id enum nested-name-specifier identifier
class-key attribute-specifier-seq identifier ; friend class-key :: identifier ; friend class-key :: simple-template-id ; friend class-key nested-name-specifier identifier ; friend class-key nested-name-specifier template simple-template-id ;In the first case, the attribute-specifier-seq, if any, appertains to the class being declared; the attributes in the attribute-specifier-seq are thereafter considered attributes of the class whenever it is named.
( expression-list )auto x = 5; // OK: x has type int const auto *v = &x, u = 6; // OK: v has type const int*, u has type const int static auto y = 0.0; // OK: y has type double auto int r; // error: auto is not a storage-class-specifier auto f() -> int; // OK: f returns int auto g() { return 0.0; } // OK: g returns double auto h(); // OK: h's return type will be deduced when it is defined
auto x = 5, *y = &x; // OK: auto is int auto a = 5, b = { 1, 2 }; // error: different types for auto
auto f() { } // OK, return type is void
auto* g() { } // error, cannot deduce auto* from void()
auto n = n; // error, n's type is unknown auto f(); void g() { &f; } // error, f's return type is unknown auto sum(int i) { if (i == 1) return i; // sum's return type is int else return sum(i-1)+i; // OK, sum's return type has been deduced }
template <class T> auto f(T t) { return t; } // return type deduced at instantiation time
typedef decltype(f(1)) fint_t; // instantiates f<int> to deduce return type
template<class T> auto f(T* t) { return *t; }
void g() { int (*p)(int*) = &f; } // instantiates both fs to determine return types,
// chooses second
auto f();
auto f() { return 42; } // return type is int
auto f(); // OK
int f(); // error, cannot be overloaded with auto f()
decltype(auto) f(); // error, auto and decltype(auto) don't match
template <typename T> auto g(T t) { return t; } // #1
template auto g(int); // OK, return type is int
template char g(char); // error, no matching template
template<> auto g(double); // OK, forward declaration with unknown return type
template <class T> T g(T t) { return t; } // OK, not functionally equivalent to #1
template char g(char); // OK, now there is a matching template
template auto g(float); // still matches #1
void h() { return g(42); } // error, ambiguous
template <typename T> struct A {
friend T frf(T);
};
auto frf(int i) { return i; } // not a friend of A<int>
template <typename T> auto f(T t) { return t; }
extern template auto f(int); // does not instantiate f<int>
int (*p)(int) = f; // instantiates f<int> to determine its return type, but an explicit
// instantiation definition is still required somewhere in the program
auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>
auto x2 = { 1, 2.0 }; // error: cannot deduce element type
auto x3{ 1, 2 }; // error: not a single element
auto x4 = { 3 }; // decltype(x4) is std::initializer_list<int>
auto x5{ 3 }; // decltype(x5) is int
const auto &i = expr;
template <class U> void f(const U& u);
int i; int&& f(); auto x2a(i); // decltype(x2a) is int decltype(auto) x2d(i); // decltype(x2d) is int auto x3a = i; // decltype(x3a) is int decltype(auto) x3d = i; // decltype(x3d) is int auto x4a = (i); // decltype(x4a) is int decltype(auto) x4d = (i); // decltype(x4d) is int& auto x5a = f(); // decltype(x5a) is int decltype(auto) x5d = f(); // decltype(x5d) is int&& auto x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list<int> decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression auto *x7a = &i; // decltype(x7a) is int* decltype(auto)*x7d = &i; // error, declared type is not plain decltype(auto)
template<class T> struct container {
container(T t) {}
template<class Iter> container(Iter beg, Iter end);
};
template<class Iter>
container(Iter b, Iter e) -> container<typename std::iterator_traits<Iter>::value_type>;
std::vector<double> v = { /* ... */ };
container c(7); // OK, deduces int for T
auto d = container(v.begin(), v.end()); // OK, deduces double for T
container e{5, 6}; // error, int is not an iterator
enum-name: identifier
enum-specifier: enum-head { enumerator-list } enum-head { enumerator-list , }
enum-head: enum-key attribute-specifier-seq enum-head-name enum-base
enum-head-name: nested-name-specifier identifier
opaque-enum-declaration: enum-key attribute-specifier-seq nested-name-specifier identifier enum-base ;
enum-key: enum enum class enum struct
enum-base: : type-specifier-seq
enumerator-list: enumerator-definition enumerator-list , enumerator-definition
enumerator-definition: enumerator enumerator = constant-expression
enumerator: identifier attribute-specifier-seqThe optional attribute-specifier-seq in the enum-head and the opaque-enum-declaration appertains to the enumeration; the attributes in that attribute-specifier-seq are thereafter considered attributes of the enumeration whenever it is named.
enum color { red, yellow, green=20, blue };
color col = red;
color* cp = &col;
if (*cp == blue) // ...
makes color a type describing various colors, and then declares
col as an object of that type, and cp as a pointer to an
object of that type.color c = 1; // error: type mismatch, no conversion from int to color int i = yellow; // OK: yellow converted to integral value 1, integral promotion
enum class Col { red, yellow, green };
int x = Col::red; // error: no Col to int conversion
Col y = Col::red;
if (y) { } // error: no Col to bool conversion
enum direction { left='l', right='r' };
void g() {
direction d; // OK
d = left; // OK
d = direction::right; // OK
}
enum class altitude { high='h', low='l' };
void h() {
altitude a; // OK
a = high; // error: high not in scope
a = altitude::low; // OK
}
struct X {
enum direction { left='l', right='r' };
int f(int i) { return i==left ? 0 : i==right ? 1 : 2; }
};
void g(X* p) {
direction d; // error: direction not in scope
int i;
i = p->f(left); // error: left not in scope
i = p->f(X::right); // OK
i = p->f(p->left); // OK
// ...
}namespace-name: identifier namespace-alias
namespace-definition: named-namespace-definition unnamed-namespace-definition nested-namespace-definition
named-namespace-definition: inline namespace attribute-specifier-seq identifier { namespace-body }
unnamed-namespace-definition: inline namespace attribute-specifier-seq { namespace-body }
nested-namespace-definition: namespace enclosing-namespace-specifier :: identifier { namespace-body }
enclosing-namespace-specifier: identifier enclosing-namespace-specifier :: identifier
namespace-body: declaration-seq
namespace Outer {
int i;
namespace Inner {
void f() { i++; } // Outer::i
int i;
void g() { i++; } // Inner::i
}
}
namespace Q {
namespace V {
void f(); // enclosing namespaces are the global namespace, Q, and Q::V
class C { void m(); };
}
void V::f() { // enclosing namespaces are the global namespace, Q, and Q::V
extern void h(); // ... so this declares Q::V::h
}
void V::C::m() { // enclosing namespaces are the global namespace, Q, and Q::V
}
}
namespace E { namespace I { B } }
namespace A::B::C {
int i;
}
namespace A {
namespace B {
namespace C {
int i;
}
}
}inline namespace unique { /* empty body */ } using namespace unique ; namespace unique { namespace-body }where inline appears if and only if it appears in the unnamed-namespace-definition and all occurrences of unique in a translation unit are replaced by the same identifier, and this identifier differs from all other identifiers in the translation unit.
namespace { int i; } // unique::i
void f() { i++; } // unique::i++
namespace A {
namespace {
int i; // A::unique::i
int j; // A::unique::j
}
void g() { i++; } // A::unique::i++
}
using namespace A;
void h() {
i++; // error: unique::i or A::unique::i
A::i++; // A::unique::i
j++; // A::unique::j
}
namespace X {
void f() { /* ... */ } // OK: introduces X::f()
namespace M {
void g(); // OK: introduces X::M::g()
}
using M::g;
void g(); // error: conflicts with X::M::g()
}
namespace Q {
namespace V {
void f();
}
void V::f() { /* ... */ } // OK
void V::g() { /* ... */ } // error: g() is not yet a member of V
namespace V {
void g();
}
}
namespace R {
void Q::V::g() { /* ... */ } // error: R doesn't enclose Q
}// Assume f and g have not yet been declared. void h(int); template <class T> void f2(T); namespace A { class X { friend void f(X); // A::f(X) is a friend class Y { friend void g(); // A::g is a friend friend void h(int); // A::h is a friend // ::h not considered friend void f2<>(int); // ::f2<>(int) is a friend }; }; // A::f, A::g and A::h are not visible here X x; void g() { f(x); } // definition of A::g void f(X) { /* ... */ } // definition of A::f void h(int) { /* ... */ } // definition of A::h // A::f, A::g and A::h are visible here and known to be friends } using A::x; void h() { A::f(x); A::X::f(x); // error: f is not a member of A::X A::X::Y::g(); // error: g is not a member of A::X::Y }
namespace Company_with_very_long_name { /* ... */ }
namespace CWVLN = Company_with_very_long_name;
namespace CWVLN = Company_with_very_long_name; // OK: duplicate
namespace CWVLN = CWVLN;using-declaration: using using-declarator-list ;
using-declarator-list: using-declarator ... using-declarator-list , using-declarator ...
using-declarator: typename nested-name-specifier unqualified-id
struct B {
void f(char);
void g(char);
enum E { e };
union { int x; };
};
struct D : B {
using B::f;
void f(int) { f('c'); } // calls B::f(char)
void g(int) { g('c'); } // recursively calls D::g(int)
};
template <typename... bases>
struct X : bases... {
using bases::g...;
};
X<B, D> x; // OK: B::g and D::g introduced
class C {
int g();
};
class D2 : public B {
using B::f; // OK: B is a base of D2
using B::e; // OK: e is an enumerator of base B
using B::x; // OK: x is a union member of base B
using C::g; // error: C isn't a base of D2
};
struct A {
template <class T> void f(T);
template <class T> struct X { };
};
struct B : A {
using A::f<double>; // ill-formed
using A::X<int>; // ill-formed
};
struct X {
int i;
static int s;
};
void f() {
using X::i; // error: X::i is a class member and this is not a member declaration.
using X::s; // error: X::s is a class member and this is not a member declaration.
}
void f();
namespace A {
void g();
}
namespace X {
using ::f; // global f
using A::g; // A's g
}
void h()
{
X::f(); // calls ::f
X::g(); // calls A::g
}
namespace A {
int i;
}
namespace A1 {
using A::i, A::i; // OK: double declaration
}
struct B {
int i;
};
struct X : B {
using B::i, B::i; // error: double member declaration
};
namespace A {
void f(int);
}
using A::f; // f is a synonym for A::f; that is, for A::f(int).
namespace A {
void f(char);
}
void foo() {
f('a'); // calls f(int), even though f(char) exists.
}
void bar() {
using A::f; // f is a synonym for A::f; that is, for A::f(int) and A::f(char).
f('a'); // calls f(char)
}
namespace A {
int x;
}
namespace B {
int i;
struct g { };
struct x { };
void f(int);
void f(double);
void g(char); // OK: hides struct g
}
void func() {
int i;
using B::i; // error: i declared twice
void f(char);
using B::f; // OK: each f is a function
f(3.5); // calls B::f(double)
using B::g;
g('a'); // calls B::g(char)
struct g g1; // g1 has class type B::g
using B::x;
using A::x; // OK: hides struct B::x
x = 99; // assigns to A::x
struct x x1; // x1 has class type B::x
}
namespace B {
void f(int);
void f(double);
}
namespace C {
void f(int);
void f(double);
void f(char);
}
void h() {
using B::f; // B::f(int) and B::f(double)
using C::f; // C::f(int), C::f(double), and C::f(char)
f('h'); // calls C::f(char)
f(1); // error: ambiguous: B::f(int) or C::f(int)?
void f(int); // error: f(int) conflicts with C::f(int) and B::f(int)
}
struct B {
virtual void f(int);
virtual void f(char);
void g(int);
void h(int);
};
struct D : B {
using B::f;
void f(int); // OK: D::f(int) overrides B::f(int);
using B::g;
void g(char); // OK
using B::h;
void h(int); // OK: D::h(int) hides B::h(int)
};
void k(D* p)
{
p->f(1); // calls D::f(int)
p->f('a'); // calls B::f(char)
p->g(1); // calls B::g(int)
p->g('a'); // calls D::g(char)
}
struct B1 {
B1(int);
};
struct B2 {
B2(int);
};
struct D1 : B1, B2 {
using B1::B1;
using B2::B2;
};
D1 d1(0); // ill-formed: ambiguous
struct D2 : B1, B2 {
using B1::B1;
using B2::B2;
D2(int); // OK: D2::D2(int) hides B1::B1(int) and B2::B2(int)
};
D2 d2(0); // calls D2::D2(int)
struct A { int x(); };
struct B : A { };
struct C : A {
using A::x;
int x(int);
};
struct D : B, C {
using C::x;
int x(double);
};
int f(D* d) {
return d->x(); // error: overload resolution selects A::x, but A is an ambiguous base class
}
class A {
private:
void f(char);
public:
void f(int);
protected:
void g();
};
class B : public A {
using A::f; // error: A::f(char) is inaccessible
public:
using A::g; // B::g is a public synonym for A::g
};using-directive: attribute-specifier-seq using namespace nested-name-specifier namespace-name ;
namespace A {
int i;
namespace B {
namespace C {
int i;
}
using namespace A::B::C;
void f1() {
i = 5; // OK, C::i visible in B and hides A::i
}
}
namespace D {
using namespace B;
using namespace C;
void f2() {
i = 5; // ambiguous, B::C::i or A::i?
}
}
void f3() {
i = 5; // uses A::i
}
}
void f4() {
i = 5; // ill-formed; neither i is visible
}
namespace M {
int i;
}
namespace N {
int i;
using namespace M;
}
void f() {
using namespace N;
i = 7; // error: both M::i and N::i are visible
}
namespace A {
int i;
}
namespace B {
int i;
int j;
namespace C {
namespace D {
using namespace A;
int j;
int k;
int a = i; // B::i hides A::i
}
using namespace D;
int k = 89; // no problem yet
int l = k; // ambiguous: C::k or D::k
int m = i; // B::i hides A::i
int n = j; // D::j hides B::j
}
}
namespace A {
class X { };
extern "C" int g();
extern "C++" int h();
}
namespace B {
void X(int);
extern "C" int g();
extern "C++" int h(int);
}
using namespace A;
using namespace B;
void f() {
X(1); // error: name X found in two namespaces
g(); // OK: name g refers to the same entity
h(); // OK: overload resolution selects A::h
}
namespace D {
int d1;
void f(char);
}
using namespace D;
int d1; // OK: no conflict with D::d1
namespace E {
int e;
void f(int);
}
namespace D { // namespace extension
int d2;
using namespace E;
void f(int);
}
void f() {
d1++; // error: ambiguous ::d1 or D::d1?
::d1++; // OK
D::d1++; // OK
d2++; // OK: D::d2
e++; // OK: E::e
f(1); // error: ambiguous: D::f(int) or E::f(int)?
f('a'); // OK: D::f(char)
}asm-definition: attribute-specifier-seq asm ( string-literal ) ;The asm declaration is conditionally-supported; its meaning is implementation-defined.
linkage-specification: extern string-literal { declaration-seq } extern string-literal declarationThe string-literal indicates the required language linkage.
complex sqrt(complex); // C++ linkage by default extern "C" { double sqrt(double); // C linkage }
extern "C" // the name f1 and its function type have C language linkage; void f1(void(*pf)(int)); // pf is a pointer to a C function extern "C" typedef void FUNC(); FUNC f2; // the name f2 has C++ language linkage and the // function's type has C language linkage extern "C" FUNC f3; // the name of function f3 and the function's type have C language linkage void (*pf2)(FUNC*); // the name of the variable pf2 has C++ linkage and the type // of pf2 is “pointer to C++ function that takes one parameter of type // pointer to C function” extern "C" { static void f4(); // the name of the function f4 has internal linkage (not C language linkage) // and the function's type has C language linkage. } extern "C" void f5() { extern void f4(); // OK: Name linkage (internal) and function type linkage (C language linkage) // obtained from previous declaration. } extern void f4(); // OK: Name linkage (internal) and function type linkage (C language linkage) // obtained from previous declaration. void f6() { extern void f4(); // OK: Name linkage (internal) and function type linkage (C language linkage) // obtained from previous declaration. }
extern "C" typedef void FUNC_c();
class C {
void mf1(FUNC_c*); // the name of the function mf1 and the member function's type have
// C++ language linkage; the parameter has type “pointer to C function”
FUNC_c mf2; // the name of the function mf2 and the member function's type have
// C++ language linkage
static FUNC_c* q; // the name of the data member q has C++ language linkage and
// the data member's type is “pointer to C function”
};
extern "C" {
class X {
void mf(); // the name of the function mf and the member function's type have
// C++ language linkage
void mf2(void(*)()); // the name of the function mf2 has C++ language linkage;
// the parameter has type “pointer to C function”
};
}
int x;
namespace A {
extern "C" int f();
extern "C" int g() { return 1; }
extern "C" int h();
extern "C" int x(); // ill-formed: same name as global-space object x
}
namespace B {
extern "C" int f(); // A::f and B::f refer to the same function
extern "C" int g() { return 1; } // ill-formed, the function g with C language linkage has two definitions
}
int A::f() { return 98; } // definition for the function f with C language linkage
extern "C" int h() { return 97; } // definition for the function h with C language linkage
// A::h and ::h refer to the same function
extern "C" double f(); static double f(); // error extern "C" int i; // declaration extern "C" { int i; // definition } extern "C" static void g(); // error
attribute-specifier-seq: attribute-specifier-seq attribute-specifier
attribute-specifier: [ [ attribute-using-prefix attribute-list ] ] alignment-specifier
alignment-specifier: alignas ( type-id ... ) alignas ( constant-expression ... )
attribute-using-prefix: using attribute-namespace :
attribute-list: attribute attribute-list , attribute attribute ... attribute-list , attribute ...
attribute: attribute-token attribute-argument-clause
attribute-token: identifier attribute-scoped-token
attribute-scoped-token: attribute-namespace :: identifier
attribute-namespace: identifier
attribute-argument-clause: ( balanced-token-seq )
balanced-token-seq: balanced-token balanced-token-seq balanced-token
balanced-token: ( balanced-token-seq ) [ balanced-token-seq ] { balanced-token-seq } any token other than a parenthesis, a bracket, or a brace
[[using CC: opt(1), debug]] // same as [[CC::opt(1), CC::debug]] void f() {} [[using CC: opt(1)]] [[CC::debug]] // same as [[CC::opt(1)]] [[CC::debug]] void g() {} [[using CC: CC::opt(1)]] // error: cannot combine using and scoped attribute token void h() {}
int p[10];
void f() {
int x = 42, y[5];
int(p[[x] { return x; }()]); // error: invalid attribute on a nested declarator-id and
// not a function-style cast of an element of p.
y[[] { return 2; }()] = 2; // error even though attributes are not allowed in this context.
int i [[vendor::attr([[]])]]; // well-formed implementation-defined attribute.
}
struct alignas(8) S {};
struct alignas(1) U {
S s;
}; // error: U specifies an alignment that is less strict than if the alignas(1) were omitted.
// Translation unit #1: struct S { int x; } s, *p = &s; // Translation unit #2: struct alignas(16) S; // error: definition of S lacks alignment, no diagnostic required extern S* p;
alignas(T) alignas(A) T buffer[N];Specifying alignas(T) ensures that the final requested alignment will not be weaker than alignof(T), and therefore the program will not be ill-formed.
alignas(double) void f(); // error: alignment applied to function alignas(double) unsigned char c[sizeof(double)]; // array of characters, suitably aligned for a double extern unsigned char c[sizeof(double)]; // no alignas necessary alignas(float) extern unsigned char c[sizeof(double)]; // error: different alignment in declaration
/* Translation unit A. */
struct foo { int* a; int* b; };
std::atomic<struct foo *> foo_head[10];
int foo_array[10][10];
[[carries_dependency]] struct foo* f(int i) {
return foo_head[i].load(memory_order_consume);
}
int g(int* x, int* y [[carries_dependency]]) {
return kill_dependency(foo_array[*x][*y]);
}
/* Translation unit B. */
[[carries_dependency]] struct foo* f(int i);
int g(int* x, int* y [[carries_dependency]]);
int c = 3;
void h(int i) {
struct foo* p;
p = f(i);
do_something_with(g(&c, p->a));
do_something_with(g(p->a, &c));
}
( string-literal )
struct [[nodiscard]] error_info { /* ... */ };
error_info enable_missile_safety_mode();
void launch_missiles();
void test_missiles() {
enable_missile_safety_mode(); // warning encouraged
launch_missiles();
}
error_info &foo();
void f() { foo(); } // warning not encouraged: not a nodiscard call, because neither
// the (reference) return type nor the function is declared nodiscard
T D1, D2, ... Dn;is usually equivalent to
T D1; T D2; ... T Dn;where T is a decl-specifier-seq and each Di is an init-declarator.
struct S { ... };
S S, T; // declare two instances of struct S
which is not equivalent to
struct S { ... };
S S;
S T; // error
Another exception is when T is auto ([dcl.spec.auto]),
for example:
auto i = 1, j = 2.0; // error: deduced types for i and j do not match
as opposed to
auto i = 1; // OK: i deduced to have type int auto j = 2.0; // OK: j deduced to have type double
declarator: ptr-declarator noptr-declarator parameters-and-qualifiers trailing-return-type
ptr-declarator: noptr-declarator ptr-operator ptr-declarator
noptr-declarator: declarator-id attribute-specifier-seq noptr-declarator parameters-and-qualifiers noptr-declarator [ constant-expression ] attribute-specifier-seq ( ptr-declarator )
parameters-and-qualifiers: ( parameter-declaration-clause ) cv-qualifier-seq ref-qualifier noexcept-specifier attribute-specifier-seq
trailing-return-type: -> type-id
ptr-operator: * attribute-specifier-seq cv-qualifier-seq & attribute-specifier-seq && attribute-specifier-seq nested-name-specifier * attribute-specifier-seq cv-qualifier-seq
cv-qualifier-seq: cv-qualifier cv-qualifier-seq
cv-qualifier: const volatile
ref-qualifier: & &&
declarator-id: ... id-expression
type-id: type-specifier-seq abstract-declarator
defining-type-id: defining-type-specifier-seq abstract-declarator
abstract-declarator: ptr-abstract-declarator noptr-abstract-declarator parameters-and-qualifiers trailing-return-type abstract-pack-declarator
ptr-abstract-declarator: noptr-abstract-declarator ptr-operator ptr-abstract-declarator
noptr-abstract-declarator: noptr-abstract-declarator parameters-and-qualifiers noptr-abstract-declarator [ constant-expression ] attribute-specifier-seq ( ptr-abstract-declarator )
abstract-pack-declarator: noptr-abstract-pack-declarator ptr-operator abstract-pack-declarator
noptr-abstract-pack-declarator: noptr-abstract-pack-declarator parameters-and-qualifiers noptr-abstract-pack-declarator [ constant-expression ] attribute-specifier-seq ...It is possible to identify uniquely the location in the abstract-declarator where the identifier would appear if the construction were a declarator in a declaration.
int // int i int * // int *pi int *[3] // int *p[3] int (*)[3] // int (*p3i)[3] int *() // int *f() int (*)(double) // int (*pf)(double)name respectively the types “int”, “pointer to int”, “array of 3 pointers to int”, “pointer to array of 3 int”, “function of (no parameters) returning pointer to int”, and “pointer to a function of (double) returning int”.
struct S {
S(int);
};
void foo(double a) {
S w(int(a)); // function declaration
S x(int()); // function declaration
S y((int(a))); // object declaration
S y((int)a); // object declaration
S z = int(a); // object declaration
}
template <class T> struct X {};
template <int N> struct Y {};
X<int()> a; // type-id
X<int(1)> b; // expression (ill-formed)
Y<int()> c; // type-id (ill-formed)
Y<int(1)> d; // expression
void foo(signed char a) {
sizeof(int()); // type-id (ill-formed)
sizeof(int(a)); // expression
sizeof(int(unsigned(a))); // type-id (ill-formed)
(int())+1; // type-id (ill-formed)
(int(a))+1; // expression
(int(unsigned(a)))+1; // type-id (ill-formed)
}
class C { };
void f(int(C)) { } // void f(int(*fp)(C c)) { }
// not: void f(int C) { }
int g(C);
void foo() {
f(1); // error: cannot convert 1 to function pointer
f(g); // OK
}
class C { };
void h(int *(C[10])); // void h(int *(*_fp)(C _parm[10]));
// not: void h(int *C[10]);
T D
T D
( D1 )the type of the contained declarator-id is the same as that of the contained declarator-id in the declaration
T D1Parentheses do not alter the type of the embedded declarator-id, but they can alter the binding of complex declarators.
* attribute-specifier-seq cv-qualifier-seq D1and the type of the identifier in the declaration T D1 is “derived-declarator-type-list T”, then the type of the identifier of D is “derived-declarator-type-list cv-qualifier-seq pointer to T”.
const int ci = 10, *pc = &ci, *const cpc = pc, **ppc; int i, *p, *const cp = &i;declare ci, a constant integer; pc, a pointer to a constant integer; cpc, a constant pointer to a constant integer; ppc, a pointer to a pointer to a constant integer; i, an integer; p, a pointer to integer; and cp, a constant pointer to integer.
i = ci; *cp = ci; pc++; pc = cpc; pc = p; ppc = &pc;
ci = 1; // error ci++; // error *pc = 2; // error cp = &ci; // error cpc++; // error p = pc; // error ppc = &p; // errorEach is unacceptable because it would either change the value of an object declared const or allow it to be changed through a cv-unqualified pointer later, for example:
*ppc = &ci; // OK, but would make p point to ci because of previous error *p = 5; // clobber ci
& attribute-specifier-seq D1 && attribute-specifier-seq D1and the type of the identifier in the declaration T D1 is “derived-declarator-type-list T”, then the type of the identifier of D is “derived-declarator-type-list reference to T”.
void f(double& a) { a += 3.14; }
// ...
double d = 0;
f(d);int v[20]; // ... int& g(int i) { return v[i]; } // ... g(3) = 7;
struct link {
link* next;
};
link* first;
void h(link*& p) { // p is a reference to pointer
p->next = first;
first = p;
p = 0;
}
void k() {
link* q = new link;
h(q);
}int i; typedef int& LRI; typedef int&& RRI; LRI& r1 = i; // r1 has the type int& const LRI& r2 = i; // r2 has the type int& const LRI&& r3 = i; // r3 has the type int& RRI& r4 = i; // r4 has the type int& RRI&& r5 = 5; // r5 has the type int&& decltype(r2)& r6 = i; // r6 has the type int& decltype(r2)&& r7 = i; // r7 has the type int&
nested-name-specifier * attribute-specifier-seq cv-qualifier-seq D1and the nested-name-specifier denotes a class, and the type of the identifier in the declaration T D1 is “derived-declarator-type-list T”, then the type of the identifier of D is “derived-declarator-type-list cv-qualifier-seq pointer to member of class nested-name-specifier of type T”.
struct X {
void f(int);
int a;
};
struct Y;
int X::* pmi = &X::a;
void (X::* pmf)(int) = &X::f;
double X::* pmd;
char Y::* pmc;declares
pmi,
pmf,
pmd
and
pmc
to be a pointer to a member of
X
of type
int,
a pointer to a member of
X
of type
void(int),
a pointer to a member of
X
of type
double
and a pointer to a member of
Y
of type
char
respectively.X obj; // ... obj.*pmi = 7; // assign 7 to an integer member of obj (obj.*pmf)(7); // call a function member of obj with the argument 7
D1 [ constant-expression ] attribute-specifier-seqand the type of the identifier in the declaration T D1 is “derived-declarator-type-list T”, then the type of the identifier of D is an array type; if the type of the identifier of D contains the auto type-specifier, the program is ill-formed.
typedef int A[5], AA[2][3]; typedef const A CA; // type is “array of 5 const int” typedef const AA CAA; // type is “array of 2 array of 3 const int”
float fa[17], *afp[17];declares an array of float numbers and an array of pointers to float numbers.
static int x3d[3][5][7];
extern int x[10];
struct S {
static int y[10];
};
int x[]; // OK: bound is 10
int S::y[]; // OK: bound is 10
void f() {
extern int x[];
int i = sizeof(x); // error: incomplete object type
}int x[3][5];
D1 ( parameter-declaration-clause ) cv-qualifier-seq ref-qualifier noexcept-specifier attribute-specifier-seqand the type of the contained declarator-id in the declaration T D1 is “derived-declarator-type-list T”, the type of the declarator-id in D is “derived-declarator-type-list noexcept function of (parameter-declaration-clause) cv-qualifier-seq ref-qualifier returning T”, where the optional noexcept is present if and only if the exception specification ([except.spec]) is non-throwing.
D1 ( parameter-declaration-clause ) cv-qualifier-seq ref-qualifier noexcept-specifier attribute-specifier-seq trailing-return-typeand the type of the contained declarator-id in the declaration T D1 is “derived-declarator-type-list T”, T shall be the single type-specifier auto.
parameter-declaration-clause: parameter-declaration-list ... parameter-declaration-list , ...
parameter-declaration-list: parameter-declaration parameter-declaration-list , parameter-declaration
parameter-declaration: attribute-specifier-seq decl-specifier-seq declarator attribute-specifier-seq decl-specifier-seq declarator = initializer-clause attribute-specifier-seq decl-specifier-seq abstract-declarator attribute-specifier-seq decl-specifier-seq abstract-declarator = initializer-clauseThe optional attribute-specifier-seq in a parameter-declaration appertains to the parameter.
typedef int FIC(int) const; FIC f; // ill-formed: does not declare a member function struct S { FIC f; // OK }; FIC S::*pm = &S::f; // OK
typedef void F();
struct S {
const F f; // OK: equivalent to: void f();
};typedef void F(); F fv; // OK: equivalent to void fv(); F fv { } // ill-formed void fv() { } // OK: definition of fv
int i,
*pi,
f(),
*fpi(int),
(*pif)(const char*, const char*),
(*fpif(int))(int);declares an integer
i,
a pointer
pi
to an integer,
a function
f
taking no arguments and returning an integer,
a function
fpi
taking an integer argument and returning a pointer to an integer,
a pointer
pif
to a function which
takes two pointers to constant characters and returns an integer,
a function
fpif
taking an integer argument and returning a pointer to a function that takes an integer argument and returns an integer.typedef int IFUNC(int); IFUNC* fpif(int);
auto fpif(int)->int(*)(int);A trailing-return-type is most useful for a type that would be more complicated to specify before the declarator-id:
template <class T, class U> auto add(T t, U u) -> decltype(t + u);
template <class T, class U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u);
template<typename... T> void f(T (* ...t)(int, int));
int add(int, int);
float subtract(int, int);
void g() {
f(add, subtract);
}void g(int = 0, ...); // OK, ellipsis is not a parameter so it can follow // a parameter with a default argument void f(int, int); void f(int, int = 7); void h() { f(3); // OK, calls f(3, 7) void f(int = 1, int); // error: does not use default from surrounding scope } void m() { void f(int, int); // has no defaults f(4); // error: wrong number of arguments void f(int, int = 5); // OK f(4); // OK, calls f(4, 5); void f(int, int = 5); // error: cannot redefine, even to same value } void n() { f(6); // OK, calls f(6, 7) }
int a = 1; int f(int); int g(int x = f(a)); // default argument: f(::a) void h() { a = 2; { int a = 3; g(); // g(f(::a)) } }
class C {
void f(int i = 3);
void g(int i, int j = 99);
};
void C::f(int i = 3) {} // error: default argument already specified in class scope
void C::g(int i = 88, int j) {} // in this translation unit, C::g can be called with no argument
void f() {
int i;
extern void g(int x = i); // error
extern void h(int x = sizeof(i)); // OK
// ...
}int a; int f(int a, int b = a); // error: parameter a used as default argument typedef int I; int g(float I, int b = I(2)); // error: parameter I found int h(int a, int b = sizeof(a)); // OK, unevaluated operand
int b;
class X {
int a;
int mem1(int i = a); // error: non-static member a used as default argument
int mem2(int i = b); // OK; use X::b
static int b;
};
int f(int = 0);
void h() {
int j = f(1);
int k = f(); // OK, means f(0)
}
int (*p1)(int) = &f;
int (*p2)() = &f; // error: type mismatch
struct A {
virtual void f(int a = 7);
};
struct B : public A {
void f(int a);
};
void m() {
B* pb = new B;
A* pa = pb;
pa->f(); // OK, calls pa->B::f(7)
pb->f(); // error: wrong number of arguments for B::f()
}function-definition: attribute-specifier-seq decl-specifier-seq declarator virt-specifier-seq function-body
function-body: ctor-initializer compound-statement function-try-block = default ; = delete ;Any informal reference to the body of a function should be interpreted as a reference to the non-terminal function-body.
static const char __func__[] = "function-name";
had been provided, where function-name is an implementation-defined string.
struct S {
S() : s(__func__) { } // OK
const char* s;
};
void f(const char* s = __func__); // error: __func__ is undeclared
attribute-specifier-seq decl-specifier-seq declarator virt-specifier-seq = default ;is called an explicitly-defaulted definition.
struct S {
constexpr S() = default; // ill-formed: implicit S() is not constexpr
S(int a = 0) = default; // ill-formed: default argument
void operator=(const S&) = default; // ill-formed: non-matching return type
~S() noexcept(false) = default; // deleted: exception specification does not match
private:
int i;
S(S&); // OK: private copy constructor
};
S::S(S&) = default; // OK: defines copy constructor
struct trivial {
trivial() = default;
trivial(const trivial&) = default;
trivial(trivial&&) = default;
trivial& operator=(const trivial&) = default;
trivial& operator=(trivial&&) = default;
~trivial() = default;
};
struct nontrivial1 {
nontrivial1();
};
nontrivial1::nontrivial1() = default; // not first declaration
attribute-specifier-seq decl-specifier-seq declarator virt-specifier-seq = delete ;is called a deleted definition.
struct onlydouble {
onlydouble() = delete; // OK, but redundant
onlydouble(std::intmax_t) = delete;
onlydouble(double);
};
struct sometype {
void* operator new(std::size_t) = delete;
void* operator new[](std::size_t) = delete;
};
sometype* p = new sometype; // error, deleted class operator new
sometype* q = new sometype[3]; // error, deleted class operator new[]
struct moveonly {
moveonly() = default;
moveonly(const moveonly&) = delete;
moveonly(moveonly&&) = default;
moveonly& operator=(const moveonly&) = delete;
moveonly& operator=(moveonly&&) = default;
~moveonly() = default;
};
moveonly* p;
moveonly q(*p); // error, deleted copy constructor
struct sometype {
sometype();
};
sometype::sometype() = delete; // ill-formed; not first declaration
attribute-specifier-seq decl-specifier-seq ref-qualifier e initializer ;where the declaration is never interpreted as a function declaration and the parts of the declaration other than the declarator-id are taken from the corresponding structured binding declaration.
auto f() -> int(&)[2]; auto [ x, y ] = f(); // x and y refer to elements in a copy of the array return value auto& [ xr, yr ] = f(); // xr and yr refer to elements in the array referred to by f's return value
initializer: brace-or-equal-initializer ( expression-list )
brace-or-equal-initializer: = initializer-clause braced-init-list
initializer-clause: assignment-expression braced-init-list
initializer-list: initializer-clause ... initializer-list , initializer-clause ...
braced-init-list: { initializer-list , } { }
expr-or-braced-init-list: expression braced-init-list
X a();
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
}
int a;
struct X {
static int a;
static int b;
};
int X::a = 1;
int X::b = a; // X::b = X::a
T x(a);
T x{a};
as well as in
new
expressions ([expr.new]),
static_cast
expressions ([expr.static.cast]),
functional notation type conversions ([expr.type.conv]),
mem-initializers, and
the braced-init-list form of a condition
is called
direct-initialization.
struct A {
int x;
struct B {
int i;
int j;
} b;
} a = { 1, { 2, 3 } };
struct base1 { int b1, b2 = 42; };
struct base2 {
base2() {
b3 = 42;
}
int b3;
};
struct derived : base1, base2 {
int d;
};
derived d1{{1, 2}, {}, 4};
derived d2{{}, {}, 4};
struct S {
int y[] = { 0 }; // error: non-static data member of incomplete type
};
struct S { int a; const char* b; int c; int d = b[a]; };
S ss = { 1, "asdf" };
struct X { int i, j, k = 42; };
X a[] = { 1, 2, 3, 4, 5, 6 };
X b[2] = { { 1, 2, 3 }, { 4, 5, 6 } };
struct A;
extern A a;
struct A {
const A& a1 { A{a,a} }; // OK
const A& a2 { A{} }; // error
};
A a{a,a}; // OK
struct S { } s;
struct A {
S s1;
int i1;
S s2;
int i2;
S s3;
int i3;
} a = {
{ }, // Required initialization
0,
s, // Required initialization
0
}; // Initialization not required for A::s3 because A::i3 is also not initialized
float y[4][3] = {
{ 1, 3, 5 },
{ 2, 4, 6 },
{ 3, 5, 7 },
};
float y[4][3] = {
1, 3, 5, 2, 4, 6, 3, 5, 7
};
union u { int a; const char* b; };
u a = { 1 };
u b = a;
u c = 1; // error
u d = { 0, "asdf" }; // error
u e = { "asdf" }; // error
int g(int) noexcept;
void f() {
int i;
int& r = i; // r refers to i
r = 1; // the value of i becomes 1
int* p = &r; // p points to i
int& rr = r; // rr refers to what r refers to, that is, to i
int (&rg)(int) = g; // rg refers to the function g
rg(i); // calls function g
int a[3];
int (&ra)[3] = a; // ra refers to the array a
ra[1] = i; // modifies a[1]
}double d = 2.0; double& rd = d; // rd refers to d const double& rcd = d; // rcd refers to d struct A { }; struct B : A { operator int&(); } b; A& ra = b; // ra refers to A subobject in b const A& rca = b; // rca refers to A subobject in b int& ir = B(); // ir refers to the result of B::operator int&
double& rd2 = 2.0; // error: not an lvalue and reference not const int i = 2; double& rd3 = i; // error: type mismatch and reference not const
struct A { };
struct B : A { } b;
extern B f();
const A& rca2 = f(); // bound to the A subobject of the B rvalue.
A&& rra = f(); // same as above
struct X {
operator B();
operator int&();
} x;
const A& r = x; // bound to the A subobject of the result of the conversion
int i2 = 42;
int&& rri = static_cast<int&&>(i2); // bound directly to i2
B&& rrb = x; // bound directly to the result of operator B
struct Banana { };
struct Enigma { operator const Banana(); };
struct Alaska { operator Banana&(); };
void enigmatic() {
typedef const Banana ConstBanana;
Banana &&banana1 = ConstBanana(); // ill-formed
Banana &&banana2 = Enigma(); // ill-formed
Banana &&banana3 = Alaska(); // ill-formed
}
const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0
double&& rrd = 2; // rrd refers to temporary with value 2.0
const volatile int cvi = 1;
const int& r2 = cvi; // error: cv-qualifier dropped
struct A { operator volatile int&(); } a;
const int& r3 = a; // error: cv-qualifier dropped
// from result of conversion function
double d2 = 1.0;
double&& rrd2 = d2; // error: initializer is lvalue of related type
struct X { operator int&(); };
int&& rri2 = X(); // error: result of conversion function is lvalue of related type
int i3 = 2;
double&& rrd3 = i3; // rrd3 refers to temporary with value 2.0
int a = {1};
std::complex<double> z{1,2};
new std::vector<std::string>{"once", "upon", "a", "time"}; // 4 string elements
f( {"Nicholas","Annemarie"} ); // pass list of two elements
return { "Norah" }; // return list of one element
int* e {}; // initialization to zero / null pointer
x = double{1}; // explicitly construct a double
std::map<std::string,int> anim = { {"bear",4}, {"cassowary",2}, {"tiger",7} };
double ad[] = { 1, 2.0 }; // OK
int ai[] = { 1, 2.0 }; // error: narrowing
struct S2 {
int m1;
double m2, m3;
};
S2 s21 = { 1, 2, 3.0 }; // OK
S2 s22 { 1.0, 2, 3 }; // error: narrowing
S2 s23 { }; // OK: default to 0,0,0
struct S {
S(std::initializer_list<double>); // #1
S(std::initializer_list<int>); // #2
S(); // #3
// ...
};
S s1 = { 1.0, 2.0, 3.0 }; // invoke #1
S s2 = { 1, 2, 3 }; // invoke #2
S s3 = { }; // invoke #3
struct Map {
Map(std::initializer_list<std::pair<std::string,int>>);
};
Map ship = {{"Sophie",14}, {"Surprise",28}};
struct S {
// no initializer-list constructors
S(int, double, double); // #1
S(); // #2
// ...
};
S s1 = { 1, 2, 3.0 }; // OK: invoke #1
S s2 { 1.0, 2, 3 }; // error: narrowing
S s3 { }; // OK: invoke #2
enum byte : unsigned char { };
byte b { 42 }; // OK
byte c = { 42 }; // error
byte d = byte{ 42 }; // OK; same value as b
byte e { -1 }; // error
struct A { byte b; };
A a1 = { { 42 } }; // error
A a2 = { byte{ 42 } }; // OK
void f(byte);
f({ 42 }); // error
enum class Handle : uint32_t { Invalid = 0 };
Handle h { 42 }; // OK
struct S {
S(std::initializer_list<double>); // #1
S(const std::string&); // #2
// ...
};
const S& r1 = { 1, 2, 3.0 }; // OK: invoke #1
const S& r2 { "Spinach" }; // OK: invoke #2
S& r3 = { 1, 2, 3 }; // error: initializer is not an lvalue
const int& i1 = { 1 }; // OK
const int& i2 = { 1.1 }; // error: narrowing
const int (&iar)[2] = { 1, 2 }; // OK: iar is bound to temporary array
struct A { int i; int j; };
A a1 { 1, 2 }; // aggregate initialization
A a2 { 1.2 }; // error: narrowing
struct B {
B(std::initializer_list<int>);
};
B b1 { 1, 2 }; // creates initializer_list<int> and calls constructor
B b2 { 1, 2.0 }; // error: narrowing
struct C {
C(int i, double j);
};
C c1 = { 1, 2.2 }; // calls constructor with arguments (1, 2.2)
C c2 = { 1.1, 2 }; // error: narrowing
int j { 1 }; // initialize to 1
int k { }; // initialize to 0
struct X {
X(std::initializer_list<double> v);
};
X x{ 1,2,3 };
const double __a[3] = {double{1}, double{2}, double{3}};
X x(std::initializer_list<double>(__a, __a+3));assuming that the implementation can construct an initializer_list object with a pair of pointers.
typedef std::complex<double> cmplx;
std::vector<cmplx> v1 = { 1, 2, 3 };
void f() {
std::vector<cmplx> v2{ 1, 2, 3 };
std::initializer_list<int> i3 = { 1, 2, 3 };
}
struct A {
std::initializer_list<int> i4;
A() : i4{ 1, 2, 3 } {} // ill-formed, would create a dangling reference
};int x = 999; // x is not a constant expression const int y = 999; const int z = 99; char c1 = x; // OK, though it might narrow (in this case, it does narrow) char c2{x}; // error: might narrow char c3{y}; // error: narrows (assuming char is 8 bits) char c4{z}; // OK: no narrowing needed unsigned char uc1 = {5}; // OK: no narrowing needed unsigned char uc2 = {-1}; // error: narrows unsigned int ui1 = {-1}; // error: narrows signed int si1 = { (unsigned int)-1 }; // error: narrows int ii = {2.0}; // error: narrows float f1 { x }; // error: might narrow float f2 { 7 }; // OK: 7 can be exactly represented as a float int f(int); int a[] = { 2, f(2), f(2.0) }; // OK: the double-to-int conversion is not at the top level
class-name: identifier simple-template-idClass-specifiers and elaborated-type-specifiers are used to make class-names.
class-specifier: class-head { member-specification }
class-head: class-key attribute-specifier-seq class-head-name class-virt-specifier base-clause class-key attribute-specifier-seq base-clause
class-head-name: nested-name-specifier class-name
class-virt-specifier: final
class-key: class struct unionA class-specifier whose class-head omits the class-head-name defines an unnamed class.
struct A;
struct A final {}; // OK: definition of struct A,
// not value-initialization of variable final
struct X {
struct C { constexpr operator int() { return 5; } };
struct B final : C{}; // OK: definition of nested class B,
// not declaration of a bit-field member final
};
struct B { int i; }; // standard-layout class
struct C : B { }; // standard-layout class
struct D : C { }; // standard-layout class
struct E : D { char : 4; }; // not a standard-layout class
struct Q {};
struct S : Q { };
struct T : Q { };
struct U : S, T { }; // not a standard-layout class
struct N { // neither trivial nor standard-layout
int i;
int j;
virtual ~N();
};
struct T { // trivial but not standard-layout
int i;
private:
int j;
};
struct SL { // standard-layout but not trivial
int i;
int j;
~SL();
};
struct POD { // both trivial and standard-layout
int i;
int j;
};
struct X { int a; };
struct Y { int a; };
X a1;
Y a2;
int a3;a1 = a2; // error: Y assigned to X a1 = a3; // error: int assigned to Xare type mismatches, and that
int f(X); int f(Y);declare an overloaded (Clause [over]) function f() and not simply a single function f() twice.
struct S { int a; };
struct S { int a; }; // error, double definition
struct stat {
// ...
};
stat gstat; // use plain stat to define variable
int stat(struct stat*); // redeclare stat as function
void f() {
struct stat* ps; // struct prefix needed to name struct stat
stat(ps); // call stat()
}
struct s { int a; };
void g() {
struct s; // hide global struct s with a block-scope declaration
s* p; // refer to local struct s
struct s { char* p; }; // define local struct s
struct s; // redeclaration, has no effect
}
struct s { int a; };
void g(int s) {
struct s* p = new struct s; // global s
p->a = s; // parameter s
}class A * A;
member-specification: member-declaration member-specification access-specifier : member-specification
member-declaration: attribute-specifier-seq decl-specifier-seq member-declarator-list ; function-definition using-declaration static_assert-declaration template-declaration deduction-guide alias-declaration empty-declaration
member-declarator-list: member-declarator member-declarator-list , member-declarator
member-declarator: declarator virt-specifier-seq pure-specifier declarator brace-or-equal-initializer identifier attribute-specifier-seq : constant-expression
virt-specifier-seq: virt-specifier virt-specifier-seq virt-specifier
virt-specifier: override final
pure-specifier: = 0
struct S {
using T = void();
T * p = 0; // OK: brace-or-equal-initializer
virtual T f = 0; // OK: pure-specifier
};
struct tnode {
char tword[20];
int count;
tnode* left;
tnode* right;
};tnode s, *sp;declares s to be a tnode and sp to be a pointer to a tnode.
struct A { int a; char b; };
struct B { const int b1; volatile char b2; };
struct C { int c; unsigned : 0; char b; };
struct D { int d; char b : 4; };
struct E { unsigned int e; char b; };
struct T1 { int a, b; };
struct T2 { int c; double d; };
union U { T1 t1; T2 t2; };
int f() {
U u = { { 1, 2 } }; // active member is t1
return u.t2.c; // OK, as if u.t1.a were nominated
}
struct X {
typedef int T;
static T count;
void f(T);
};
void X::f(T t = count) { }
typedef void fv();
typedef void fvc() const;
struct S {
fv memfunc1; // equivalent to: void memfunc1();
void memfunc2();
fvc memfunc3; // equivalent to: void memfunc3() const;
};
fv S::* pmfv1 = &S::memfunc1;
fv S::* pmfv2 = &S::memfunc2;
fvc S::* pmfv3 = &S::memfunc3;
struct tnode {
char tword[20];
int count;
tnode* left;
tnode* right;
void set(const char*, tnode* l, tnode* r);
};
void tnode::set(const char* w, tnode* l, tnode* r) {
count = strlen(w)+1;
if (sizeof(tword)<=count)
perror("tnode string too long");
strcpy(tword,w);
left = l;
right = r;
}
void f(tnode n1, tnode n2) {
n1.set("abc",&n2,0);
n2.set("def",0,0);
}
struct s {
int a;
int f() const;
int g() { return a++; }
int h() const { return a++; } // error
};
int s::f() const { return a; }
struct process {
static void reschedule();
};
process& g();
void f() {
process::reschedule(); // OK: no object necessary
g().reschedule(); // g() is called
}
int g();
struct X {
static int g();
};
struct Y : X {
static int i;
};
int Y::i = g(); // equivalent to Y::g();
class process {
static process* run_chain;
static process* running;
};
process* process::running = get_main();
process* process::run_chain = running;identifier attribute-specifier-seq : constant-expressionspecifies a bit-field; its length is set off from the bit-field name by a colon.
enum BOOL { FALSE=0, TRUE=1 };
struct A {
BOOL b:1;
};
A a;
void f() {
a.b = TRUE;
if (a.b == TRUE) // yields true
{ /* ... */ }
}
int x;
int y;
struct enclose {
int x;
static int s;
struct inner {
void f(int i) {
int a = sizeof(x); // OK: operand of sizeof is an unevaluated operand
x = i; // error: assign to enclose::x
s = i; // OK: assign to enclose::s
::x = i; // OK: assign to global x
y = i; // OK: assign to global y
}
void g(enclose* p, int i) {
p->x = i; // OK: assign to enclose::x
}
};
};
inner* p = 0; // error: inner not in scope
struct enclose {
struct inner {
static int x;
void f(int i);
};
};
int enclose::inner::x = 1;
void enclose::inner::f(int i) { /* ... */ }
class E {
class I1; // forward declaration of nested class
class I2;
class I1 { }; // definition of nested class
};
class E::I2 { }; // definition of nested class
struct X {
typedef int I;
class Y { /* ... */ };
I a;
};
I b; // error
Y c; // error
X::Y d; // OK
X::I e; // OK
union U {
int i;
float f;
std::string s;
};
union A { int x; int y[4]; };
struct B { A a; };
union C { B b; int k; };
int f() {
C c; // does not start lifetime of any union member
c.b.a.y[3] = 4; // OK: S(c.b.a.y[3]) contains c.b and c.b.a.y;
// creates objects to hold union members c.b and c.b.a.y
return c.b.a.y[3]; // OK: c.b.a.y refers to newly created object (see [basic.life])
}
struct X { const int a; int b; };
union Y { X x; int k; };
void g() {
Y y = { { 1, 2 } }; // OK, y.x is active union member ([class.mem])
int n = y.x.a;
y.k = 4; // OK: ends lifetime of y.x, y.k is active member of union
y.x.b = n; // undefined behavior: y.x.b modified outside its lifetime,
// S(y.x.b) is empty because X's default constructor is deleted,
// so union member y.x's lifetime does not implicitly start
}u.m.~M(); new (&u.n) N;
union { member-specification } ;is called an anonymous union; it defines an unnamed type and an unnamed object of that type called an anonymous union object.
union U {
int x = 0;
union {
int k;
};
union {
int z;
int y = 1; // error: initialization for second variant member of U
};
};
int x;
void f() {
static int s;
int x;
const int N = 5;
extern int q();
struct local {
int g() { return x; } // error: odr-use of automatic variable x
int h() { return s; } // OK
int k() { return ::x; } // OK
int l() { return q(); } // OK
int m() { return N; } // OK: not an odr-use
int* n() { return &N; } // error: odr-use of automatic variable N
};
}
local* p = 0; // error: local not in scope
base-clause: : base-specifier-list
base-specifier-list: base-specifier ... base-specifier-list , base-specifier ...
base-specifier: attribute-specifier-seq class-or-decltype attribute-specifier-seq virtual access-specifier class-or-decltype attribute-specifier-seq access-specifier virtual class-or-decltype
class-or-decltype: nested-name-specifier class-name nested-name-specifier template simple-template-id decltype-specifier
access-specifier: private protected publicThe optional attribute-specifier-seq appertains to the base-specifier.
class A { /* ... */ };
class B { /* ... */ };
class C { /* ... */ };
class D : public A, public B, public C { /* ... */ };
class X { /* ... */ };
class Y : public X, public X { /* ... */ }; // ill-formed
class L { public: int next; /* ... */ };
class A : public L { /* ... */ };
class B : public L { /* ... */ };
class C : public A, public B { void f(); /* ... */ }; // well-formed
class D : public A, public L { void f(); /* ... */ }; // well-formed
void C::f() { A::next = B::next; } // well-formed
Without the A:: or B:: qualifiers, the definition of
C::f above would be ill-formed because of
ambiguity ([class.member.lookup]).
class V { /* ... */ };
class A : virtual public V { /* ... */ };
class B : virtual public V { /* ... */ };
class C : public A, public B { /* ... */ };
class B { /* ... */ };
class X : virtual public B { /* ... */ };
class Y : virtual public B { /* ... */ };
class Z : public B { /* ... */ };
class AA : public X, public Y, public Z { /* ... */ };
struct A { int x; }; // S(x,A) = { { A::x }, { A } }
struct B { float x; }; // S(x,B) = { { B::x }, { B } }
struct C: public A, public B { }; // S(x,C) = { invalid, { A in C, B in C } }
struct D: public virtual C { }; // S(x,D) = S(x,C)
struct E: public virtual C { char x; }; // S(x,E) = { { E::x }, { E } }
struct F: public D, public E { }; // S(x,F) = S(x,E)
int main() {
F f;
f.x = 0; // OK, lookup finds E::x
}
struct A {
int f();
};
struct B {
int f();
};
struct C : A, B {
int f() { return A::f() + B::f(); }
};
struct V {
int v;
};
struct A {
int a;
static int s;
enum { e };
};
struct B : A, virtual V { };
struct C : A, virtual V { };
struct D : B, C { };
void f(D* pd) {
pd->v++; // OK: only one v (virtual)
pd->s++; // OK: only one s (static)
int i = pd->e; // OK: only one e (enumerator)
pd->a++; // error, ambiguous: two as in D
}
struct V { int f(); int x; };
struct W { int g(); int y; };
struct B : virtual V, W {
int f(); int x;
int g(); int y;
};
struct C : virtual V, W { };
struct D : B, C { void glorp(); };
void D::glorp() {
x++; // OK: B::x hides V::x
f(); // OK: B::f() hides V::f()
y++; // error: B::y and C's W::y
g(); // error: B::g() and C's W::g()
}
struct V { };
struct A { };
struct B : A, virtual V { };
struct C : A, virtual V { };
struct D : B, C { };
void g() {
D d;
B* pb = &d;
A* pa = &d; // error, ambiguous: C's A or B's A?
V* pv = &d; // OK: only one V subobject
}
struct B1 {
void f();
static void f(int);
int i;
};
struct B2 {
void f(double);
};
struct I1: B1 { };
struct I2: B1 { };
struct D: I1, I2, B2 {
using B1::f;
using B2::f;
void g() {
f(); // Ambiguous conversion of this
f(0); // Unambiguous (static)
f(0.0); // Unambiguous (only one B2)
int B1::* mpB1 = &D::i; // Unambiguous
int D::* mpD = &D::i; // Ambiguous conversion
}
};
struct A {
virtual void f();
};
struct B : virtual A {
virtual void f();
};
struct C : B , virtual A {
using A::f;
};
void foo() {
C c;
c.f(); // calls B::f, the final overrider
c.C::f(); // calls A::f because of the using-declaration
}
struct A { virtual void f(); };
struct B : A { };
struct C : A { void f(); };
struct D : B, C { }; // OK: A::f and C::f are the final overriders
// for the B and C subobjects, respectively
struct B {
virtual void f();
};
struct D : B {
void f(int);
};
struct D2 : D {
void f();
};
the function f(int) in class D hides the virtual
function f() in its base class B; D::f(int) is
not a virtual function.
struct B {
virtual void f() const final;
};
struct D : B {
void f() const; // error: D::f attempts to override final B::f
};
struct B {
virtual void f(int);
};
struct D : B {
virtual void f(long) override; // error: wrong signature overriding B::f
virtual void f(int) override; // OK
};
class B { };
class D : private B { friend class Derived; };
struct Base {
virtual void vf1();
virtual void vf2();
virtual void vf3();
virtual B* vf4();
virtual B* vf5();
void f();
};
struct No_good : public Base {
D* vf4(); // error: B (base class of D) inaccessible
};
class A;
struct Derived : public Base {
void vf1(); // virtual and overrides Base::vf1()
void vf2(int); // not virtual, hides Base::vf2()
char vf3(); // error: invalid difference in return type only
D* vf4(); // OK: returns pointer to derived class
A* vf5(); // error: returns pointer to incomplete class
void f();
};
void g() {
Derived d;
Base* bp = &d; // standard conversion:
// Derived* to Base*
bp->vf1(); // calls Derived::vf1()
bp->vf2(); // calls Base::vf2()
bp->f(); // calls Base::f() (not virtual)
B* p = bp->vf4(); // calls Derived::pf() and converts the
// result to B*
Derived* dp = &d;
D* q = dp->vf4(); // calls Derived::pf() and does not
// convert the result to B*
dp->vf2(); // ill-formed: argument mismatch
}
struct A {
virtual void f();
};
struct B1 : A { // note non-virtual derivation
void f();
};
struct B2 : A {
void f();
};
struct D : B1, B2 { // D has two separate A subobjects
};
void foo() {
D d;
// A* ap = &d; // would be ill-formed: ambiguous
B1* b1p = &d;
A* ap = b1p;
D* dp = &d;
ap->f(); // calls D::B1::f
dp->f(); // ill-formed: ambiguous
}
In class D above there are two occurrences of class A
and hence two occurrences of the virtual member function A::f.
struct A {
virtual void f();
};
struct VB1 : virtual A { // note virtual derivation
void f();
};
struct VB2 : virtual A {
void f();
};
struct Error : VB1, VB2 { // ill-formed
};
struct Okay : VB1, VB2 {
void f();
};
Both VB1::f and VB2::f override A::f but there
is no overrider of both of them in class Error.
class point { /* ... */ };
class shape { // abstract class
point center;
public:
point where() { return center; }
void move(point p) { center=p; draw(); }
virtual void rotate(int) = 0; // pure virtual
virtual void draw() = 0; // pure virtual
};shape x; // error: object of abstract class shape* p; // OK shape f(); // error void g(shape); // error shape& h(shape&); // OK
class ab_circle : public shape {
int radius;
public:
void rotate(int) { }
// ab_circle::draw() is a pure virtual
};
class circle : public shape {
int radius;
public:
void rotate(int) { }
void draw(); // a definition is required somewhere
};
would make class circle non-abstract and a definition of
circle::draw() must be provided.
class X {
int a; // X::a is private by default
};
struct S {
int a; // S::a is public by default
};
class A {
class B { };
public:
typedef B BB;
};
void f() {
A::BB x; // OK, typedef name A::BB is public
A::B y; // access error, A::B is private
}
class A {
typedef int I; // private member
I f();
friend I g(I);
static I x;
template<int> struct Q;
template<int> friend struct R;
protected:
struct B { };
};
A::I A::f() { return 0; }
A::I g(A::I p = A::x);
A::I g(A::I p) { return 0; }
A::I A::x = 0;
template<A::I> struct A::Q { };
template<A::I> struct R { };
struct D: A::B, A { };
class B { };
template <class T> class C {
protected:
typedef T TT;
};
template <class U, class V = typename U::TT>
class D : public U { };
D <C<B> >* d; // access error, C::TT is protected
access-specifier : member-specificationAn access-specifier specifies the access rules for members following it until the end of the class or until another access-specifier is encountered.
class X {
int a; // X::a is private by default: class used
public:
int b; // X::b is public
int c; // X::c is public
};
struct S {
int a; // S::a is public by default: struct used
protected:
int b; // S::b is protected
private:
int c; // S::c is private
public:
int d; // S::d is public
};
struct S {
class A;
enum E : int;
private:
class A { }; // error: cannot change access
enum E: int { e0 }; // error: cannot change access
};
class A { };
class B : private A { };
class C : public B {
A* p; // error: injected-class-name A is inaccessible
::A* q; // OK
};
class B { /* ... */ };
class D1 : private B { /* ... */ };
class D2 : public B { /* ... */ };
class D3 : B { /* ... */ }; // B private by default
struct D4 : public B { /* ... */ };
struct D5 : private B { /* ... */ };
struct D6 : B { /* ... */ }; // B public by default
class D7 : protected B { /* ... */ };
struct D8 : protected B { /* ... */ };
class B {
public:
int mi; // non-static member
static int si; // static member
};
class D : private B {
};
class DD : public D {
void f();
};
void DD::f() {
mi = 3; // error: mi is private in D
si = 3; // error: si is private in D
::B b;
b.mi = 3; // OK (b.mi is different from this->mi)
b.si = 3; // OK (b.si is different from this->si)
::B::si = 3; // OK
::B* bp1 = this; // error: B is a private base class
::B* bp2 = (::B*)this; // OK with cast
bp2->mi = 3; // OK: access through a pointer to B.
}
class B {
public:
int m;
};
class S: private B {
friend class N;
};
class N: private S {
void f() {
B* p = this; // OK because class S satisfies the fourth condition above: B is a base class of N
// accessible in f() because B is an accessible base class of S and S is an accessible
// base class of N.
}
};
class B;
class A {
private:
int i;
friend void f(B*);
};
class B : public A { };
void f(B* p) {
p->i = 1; // OK: B* can be implicitly converted to A*, and f has access to i in A
}
class X {
int a;
friend void friend_set(X*, int);
public:
void member_set(int);
};
void friend_set(X* p, int i) { p->a = i; }
void X::member_set(int i) { a = i; }
void f() {
X obj;
friend_set(&obj,10);
obj.member_set(10);
}
class A {
class B { };
friend class X;
};
struct X : A::B { // OK: A::B accessible to friend
A::B mx; // OK: A::B accessible to member of friend
class Y {
A::B my; // OK: A::B accessible to nested member of friend
};
};
class X {
enum { a=100 };
friend class Y;
};
class Y {
int v[X::a]; // OK, Y is a friend of X
};
class Z {
int v[X::a]; // error: X::a is private
};
class A {
friend class B { }; // error: cannot define class in friend declaration
};friend elaborated-type-specifier ; friend simple-type-specifier ; friend typename-specifier ;
class C;
typedef C Ct;
class X1 {
friend C; // OK: class C is a friend
};
class X2 {
friend Ct; // OK: class C is a friend
friend D; // error: no type-name D in scope
friend class D; // OK: elaborated-type-specifier declares new class
};
template <typename T> class R {
friend T;
};
R<C> rc; // class C is a friend of R<C>
R<int> Ri; // OK: "friend int;" is ignored
class Y {
friend char* X::foo(int);
friend X::X(char); // constructors can be friends
friend X::~X(); // destructors can be friends
};
class M {
friend void f() { } // definition of global f, a friend of M,
// not the definition of a member function
};
class A {
friend class B;
int a;
};
class B {
friend class C;
};
class C {
void f(A* p) {
p->a++; // error: C is not a friend of A despite being a friend of a friend
}
};
class D : public B {
void f(A* p) {
p->a++; // error: D is not a friend of A despite being derived from a friend
}
};
class X;
void a();
void f() {
class Y;
extern void b();
class A {
friend class X; // OK, but X is a local class, not ::X
friend class Y; // OK
friend class Z; // OK, introduces local class Z
friend void a(); // error, ::a is not considered
friend void b(); // OK
friend void c(); // error
};
X* px; // OK, but ::X is found
Z* pz; // error, no Z is found
}
class B {
protected:
int i;
static int j;
};
class D1 : public B {
};
class D2 : public B {
friend void fr(B*,D1*,D2*);
void mem(B*,D1*);
};
void fr(B* pb, D1* p1, D2* p2) {
pb->i = 1; // ill-formed
p1->i = 2; // ill-formed
p2->i = 3; // OK (access through a D2)
p2->B::i = 4; // OK (access through a D2, even though naming class is B)
int B::* pmi_B = &B::i; // ill-formed
int B::* pmi_B2 = &D2::i; // OK (type of &D2::i is int B::*)
B::j = 5; // ill-formed (not a friend of naming class B)
D2::j = 6; // OK (because refers to static member)
}
void D2::mem(B* pb, D1* p1) {
pb->i = 1; // ill-formed
p1->i = 2; // ill-formed
i = 3; // OK (access through this)
B::i = 4; // OK (access through this, qualification ignored)
int B::* pmi_B = &B::i; // ill-formed
int B::* pmi_B2 = &D2::i; // OK
j = 5; // OK (because j refers to static member)
B::j = 6; // OK (because B::j refers to static member)
}
void g(B* pb, D1* p1, D2* p2) {
pb->i = 1; // ill-formed
p1->i = 2; // ill-formed
p2->i = 3; // ill-formed
}
class B {
public:
virtual int f();
};
class D : public B {
private:
int f();
};
void f() {
D d;
B* pb = &d;
D* pd = &d;
pb->f(); // OK: B::f() is public, D::f() is invoked
pd->f(); // error: D::f() is private
}
class E {
int x;
class B { };
class I {
B b; // OK: E::I can access E::B
int y;
void f(E* p, int i) {
p->x = i; // OK: E::I can access E::x
}
};
int g(I* p) {
return p->y; // error: I::y is private
}
};
struct A { }; // implicitly declared A::operator=
struct B : A {
B& operator=(const B &);
};
B& B::operator=(const B& s) {
this->A::operator=(s); // well formed
return *this;
}ptr-declarator ( parameter-declaration-clause ) noexcept-specifier attribute-specifier-seqwhere the ptr-declarator consists solely of an id-expression, an optional attribute-specifier-seq, and optional surrounding parentheses, and the id-expression has one of the following forms:
struct S {
S(); // declares the constructor
};
S::S() { } // defines the constructor
struct C;
void no_opt(C*);
struct C {
int c;
C() : c(0) { no_opt(this); }
};
const C cobj;
void no_opt(C* cptr) {
int i = cobj.c * 100; // value of cobj.c is unspecified
cptr->c = 1;
cout << cobj.c * 100 // value of cobj.c is unspecified
<< '\n';
}
extern struct D d;
struct D {
D(int a) : a(a), b(d.a) {}
int a, b;
};
D d = D(1); // value of d.b is unspecified
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);
}X(2) is constructed in the space used to hold f()'s argument and
Y(3) is constructed in the space used to hold g()'s argument.
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
struct S {
S();
S(int);
friend S operator+(const S&, const S&);
~S();
};
S obj1;
const S& cr = S(16)+S(23);
S obj2;
struct X {
operator int();
};
struct Y {
operator X();
};
Y a;
int b = a; // error, a.operator X().operator int() not tried
int c = X(a); // OK: a.operator X().operator int()
struct X {
operator int();
};
struct Y : X {
operator char();
};
void f(Y& a) {
if (a) { // ill-formed: X::operator int() or Y::operator char()
}
}
struct X {
X(int);
X(const char*, int =0);
X(int, int);
};
void f(X arg) {
X a = 1; // a = X(1)
X b = "Jessie"; // b = X("Jessie",0)
a = 2; // a = X(2)
f(3); // f(X(3))
f({1, 2}); // f(X(1,2))
}
struct Z {
explicit Z();
explicit Z(int);
explicit Z(int, int);
};
Z a; // OK: default-initialization performed
Z b{}; // OK: direct initialization syntax used
Z c = {}; // error: copy-list-initialization
Z a1 = 1; // error: no implicit conversion
Z a3 = Z(1); // OK: direct initialization syntax used
Z a2(1); // OK: direct initialization syntax used
Z* p = new Z(1); // OK: direct initialization syntax used
Z a4 = (Z)1; // OK: explicit cast used
Z a5 = static_cast<Z>(1); // OK: explicit cast used
Z a6 = { 3, 4 }; // error: no implicit conversion
conversion-function-id: operator conversion-type-id
conversion-type-id: type-specifier-seq conversion-declarator
conversion-declarator: ptr-operator conversion-declaratorspecifies a conversion from X to the type specified by the conversion-type-id.
class Y { };
struct Z {
explicit operator Y() const;
};
void h(Z z) {
Y y1(z); // OK: direct-initialization
Y y2 = z; // ill-formed: copy-initialization
Y y3 = (Y)z; // OK: cast notation
}
void g(X a, X b) {
int i = (a) ? 1+a : 0;
int j = (a&&b) ? a+b : i;
if (a) {
}
}
struct S {
operator auto() const { return 10; } // OK
template<class T>
operator auto() const { return 1.2; } // error: conversion function template
};ptr-declarator ( parameter-declaration-clause ) noexcept-specifier attribute-specifier-seqwhere the ptr-declarator consists solely of an id-expression, an optional attribute-specifier-seq, and optional surrounding parentheses, and the id-expression has one of the following forms:
struct B {
virtual ~B() { }
};
struct D : B {
~D() { }
};
D D_object;
typedef B B_alias;
B* B_ptr = &D_object;
void f() {
D_object.B::~B(); // calls B's destructor
B_ptr->~B(); // calls D's destructor
B_ptr->~B_alias(); // calls D's destructor
B_ptr->B_alias::~B(); // calls B's destructor
B_ptr->B_alias::~B_alias(); // calls B's destructor
}
void* operator new(std::size_t, void* p) { return p; }
struct X {
X(int);
~X();
};
void f(X* p);
void g() { // rare, specialized use:
char* buf = new char[sizeof(X)];
X* p = new(buf) X(222); // use buf[] and initialize
f(p);
p->X::~X(); // cleanup
}
class Arena;
struct B {
void* operator new(std::size_t, Arena*);
};
struct D1 : B {
};
Arena* ap;
void foo(int i) {
new (ap) D1; // calls B::operator new(std::size_t, Arena*)
new D1[i]; // calls ::operator new[](std::size_t)
new D1; // ill-formed: ::operator new(std::size_t) hidden
}
class X {
void operator delete(void*);
void operator delete[](void*, std::size_t);
};
class Y {
void operator delete(void*, std::size_t);
void operator delete[](void*);
};
struct B {
virtual ~B();
void operator delete(void*, std::size_t);
};
struct D : B {
void operator delete(void*);
};
void f() {
B* bp = new D;
delete bp; // 1: uses D::operator delete(void*)
}
Here, storage for the non-array object of class
D
is deallocated by
D::operator delete(),
due to the virtual destructor.
struct B {
virtual ~B();
void operator delete[](void*, std::size_t);
};
struct D : B {
void operator delete[](void*, std::size_t);
};
void f(int i) {
D* dp = new D[i];
delete [] dp; // uses D::operator delete[](void*, std::size_t)
B* bp = new D[i];
delete[] bp; // undefined behavior
}
struct complex {
complex();
complex(double);
complex(double,double);
};
complex sqrt(complex,complex);
complex a(1); // initialize by a call of complex(double)
complex b = a; // initialize by a copy of a
complex c = complex(1,2); // construct complex(1,2) using complex(double,double),
// copy/move it into c
complex d = sqrt(b,c); // call sqrt(complex,complex) and copy/move the result into d
complex e; // initialize by a call of complex()
complex f = 3; // construct complex(3) using complex(double), copy/move it into f
complex g = { 1, 2 }; // initialize by a call of complex(double, double)
complex v[6] = { 1, complex(1,2), complex(), 2 };
struct X {
int i;
float f;
complex c;
} x = { 99, 88.8, 77.7 };
struct A { A(); };
typedef A global_A;
struct B { };
struct C: public A, public B { C(); };
C::C(): global_A() { } // mem-initializer for base A
struct A { A(); };
struct B: public virtual A { };
struct C: public A, public B { C(); };
C::C(): A() { } // ill-formed: which A?
struct C {
C( int ) { } // #1: non-delegating constructor
C(): C(42) { } // #2: delegates to #1
C( char c ) : C(42.0) { } // #3: ill-formed due to recursion with #4
C( double d ) : C('a') { } // #4: ill-formed due to recursion with #3
};
struct B1 { B1(int); /* ... */ };
struct B2 { B2(int); /* ... */ };
struct D : B1, B2 {
D(int);
B1 b;
const int c;
};
D::D(int a) : B2(a+1), B1(a+2), c(a+3), b(a+4) { /* ... */ }
D d(10);
struct A {
A();
};
struct B {
B(int);
};
struct C {
C() { } // initializes members as follows:
A a; // OK: calls A::A()
const B b; // error: B has no default constructor
int i; // OK: i has indeterminate value
int j = 5; // OK: j has the value 5
};
struct A {
A() = default; // OK
A(int v) : v(v) { } // OK
const int& v = 42; // OK
};
A a1; // error: ill-formed binding of temporary to reference
A a2(1); // OK, unfortunately
struct V {
V();
V(int);
};
struct A : virtual V {
A();
A(int);
};
struct B : virtual V {
B();
B(int);
};
struct C : A, B, virtual V {
C();
C(int);
};
A::A(int i) : V(i) { /* ... */ }
B::B(int i) { /* ... */ }
C::C(int i) { /* ... */ }
V v(1); // use V(int)
A a(2); // use V(int)
B b(3); // use V()
C c(4); // use V()
class X {
int a;
int b;
int i;
int j;
public:
const int& r;
X(int i): r(a), b(i), i(i), j(this->i) { }
};
class A {
public:
A(int);
};
class B : public A {
int j;
public:
int f();
B() : A(f()), // undefined: calls member function but base A not yet initialized
j(f()) { } // well-defined: bases are all initialized
};
class C {
public:
C(int);
};
class D : public B, C {
int i;
public:
D() : C(f()), // undefined: calls member function but base C not yet initialized
i(f()) { } // well-defined: bases are all initialized
};
template<class... Mixins>
class X : public Mixins... {
public:
X(const Mixins&... mixins) : Mixins(mixins)... { }
};
struct B1 {
B1(int, ...) { }
};
struct B2 {
B2(double) { }
};
int get();
struct D1 : B1 {
using B1::B1; // inherits B1(int, ...)
int x;
int y = get();
};
void test() {
D1 d(2, 3, 4); // OK: B1 is initialized by calling B1(2, 3, 4),
// then d.x is default-initialized (no initialization is performed),
// then d.y is initialized by calling get()
D1 e; // error: D1 has a deleted default constructor
}
struct D2 : B2 {
using B2::B2;
B1 b;
};
D2 f(1.0); // error: B1 has a deleted default constructor
struct W { W(int); };
struct X : virtual W { using W::W; X() = delete; };
struct Y : X { using X::X; };
struct Z : Y, virtual W { using Y::Y; };
Z z(0); // OK: initialization of Y does not invoke default constructor of X
template<class T> struct Log : T {
using T::T; // inherits all constructors from class T
~Log() { std::clog << "Destroying wrapper" << std::endl; }
};
struct A { A(int); };
struct B : A { using A::A; };
struct C1 : B { using B::B; };
struct C2 : B { using B::B; };
struct D1 : C1, C2 {
using C1::C1;
using C2::C2;
};
struct V1 : virtual B { using B::B; };
struct V2 : virtual B { using B::B; };
struct D2 : V1, V2 {
using V1::V1;
using V2::V2;
};
D1 d1(0); // ill-formed: ambiguous
D2 d2(0); // OK: initializes virtual B base class, which initializes the A base class
// then initializes the V1 and V2 base classes as if by a defaulted default constructor
struct M { M(); M(int); };
struct N : M { using M::M; };
struct O : M {};
struct P : N, O { using N::N; using O::O; };
P p(0); // OK: use M(0) to initialize N's base class,
// use M() to initialize O's base class
struct X { int i; };
struct Y : X { Y(); }; // non-trivial
struct A { int a; };
struct B : public A { int j; Y y; }; // non-trivial
extern B bobj;
B* pb = &bobj; // OK
int* p1 = &bobj.a; // undefined, refers to base class member
int* p2 = &bobj.y.i; // undefined, refers to member's member
A* pa = &bobj; // undefined, upcast to a base class type
B bobj; // definition of bobj
extern X xobj;
int* p3 = &xobj.i; // OK, X is a trivial class
X xobj;
struct W { int j; };
struct X : public virtual W { };
struct Y {
int* p;
X x;
Y() : p(&x.j) { // undefined, x is not yet constructed
}
};
struct A { };
struct B : virtual A { };
struct C : B { };
struct D : virtual A { D(A*); };
struct X { X(A*); };
struct E : C, D, X {
E() : D(this), // undefined: upcast from E* to A* might use path E* → D* → A*
// but D is not constructed
// “D((C*)this)” would be defined: E* → C* is defined because E() has started,
// and C* → A* is defined because C is fully constructed
X(this) {} // defined: upon construction of X, C/B/D/A sublattice is fully constructed
};
struct V {
virtual void f();
virtual void g();
};
struct A : virtual V {
virtual void f();
};
struct B : virtual V {
virtual void g();
B(V*, A*);
};
struct D : A, B {
virtual void f();
virtual void g();
D() : B((A*)this, this) { }
};
B::B(V* v, A* a) {
f(); // calls V::f, not A::f
g(); // calls B::g, not D::g
v->g(); // v is base of B, the call is well-defined, calls B::g
a->f(); // undefined behavior, a's type not a base of B
}
struct V {
virtual void f();
};
struct A : virtual V { };
struct B : virtual V {
B(V*, A*);
};
struct D : A, B {
D() : B((A*)this, this) { }
};
B::B(V* v, A* a) {
typeid(*this); // type_info for B
typeid(*v); // well-defined: *v has type V, a base of B yields type_info for B
typeid(*a); // undefined behavior: type A not a base of B
dynamic_cast<B*>(v); // well-defined: v of type V*, V base of B results in B*
dynamic_cast<B*>(a); // undefined behavior, a has type A*, A not a base of B
}
struct X {
X(); // default constructor
X(X&); // copy constructor with a non-const parameter
};
const X cx;
X x = cx; // error: X::X(X&) cannot copy cx into x
struct S {
template<typename T> S(T);
S();
};
S g;
void h() {
S a(g); // does not instantiate the member template to produce S::S<S>(S);
// uses the implicitly declared copy constructor
}X::X(const X&)
X::X(X&)
struct X {
X();
X& operator=(X&);
};
const X cx;
X x;
void f() {
x = cx; // error: X::operator=(X&) cannot assign cx into x
}X& X::operator=(const X&)
X& X::operator=(X&)
struct S {
int a;
S& operator=(const S&) = default;
};will not have a default move assignment operator implicitly declared because the
copy assignment operator has been user-declared.
struct S {
int a;
S& operator=(const S&) = default;
S& operator=(S&&) = default;
};X& X::operator=(X&&);
class Thing {
public:
Thing();
~Thing();
Thing(const Thing&);
};
Thing f() {
Thing t;
return t;
}
Thing t2 = f();
struct A {
void *p;
constexpr A(): p(this) {}
};
constexpr A g() {
A a;
return a;
}
constexpr A a; // well-formed, a.p points to a
constexpr A b = g(); // well-formed, b.p points to b
void g() {
A c = g(); // well-formed, c.p may point to c or to an ephemeral temporary
}
class Thing {
public:
Thing();
~Thing();
Thing(Thing&&);
private:
Thing(const Thing&);
};
Thing f(bool b) {
Thing t;
if (b)
throw t; // OK: Thing(Thing&&) used (or elided) to throw t
return t; // OK: Thing(Thing&&) used (or elided) to return t
}
Thing t2 = f(false); // OK: no extra copy/move performed, t2 constructed by call to f
struct Weird {
Weird();
Weird(Weird&);
};
Weird g() {
Weird w;
return w; // OK: first overload resolution fails, second overload resolution selects Weird(Weird&)
}
class X {
static void f();
void f(); // ill-formed
void f() const; // ill-formed
void f() const volatile; // ill-formed
void g();
void g() const; // OK: no static g
void g() const volatile; // OK: no static g
};
class Y {
void h() &;
void h() const &; // OK
void h() &&; // OK, all declarations have a ref-qualifier
void i() &;
void i() const; // ill-formed, prior declaration of i
// has a ref-qualifier
};typedef int Int; void f(int i); void f(Int i); // OK: redeclaration of f(int) void f(int i) { /* ... */ } void f(Int i) { /* ... */ } // error: redefinition of f(int)
int f(char*); int f(char[]); // same as f(char*); int f(char[7]); // same as f(char*); int f(char[9]); // same as f(char*); int g(char(*)[10]); int g(char[5][10]); // same as g(char(*)[10]); int g(char[7][10]); // same as g(char(*)[10]); int g(char(*)[20]); // different from g(char(*)[10]);
void h(int()); void h(int (*)()); // redeclaration of h(int()) void h(int x()) { } // definition of h(int()) void h(int (*x)()) { } // ill-formed: redefinition of h(int())
typedef const int cInt; int f (int); int f (const int); // redeclaration of f(int) int f (int) { /* ... */ } // definition of f(int) int f (cInt) { /* ... */ } // error: redefinition of f(int)
void f (int i, int j); void f (int i, int j = 99); // OK: redeclaration of f(int, int) void f (int i = 88, int j); // OK: redeclaration of f(int, int) void f (); // OK: overloaded declaration of f void prog () { f (1, 2); // OK: call f(int, int) f (1); // OK: call f(int, int) f (); // Error: f(int, int) or f()? }
void f(const char*);
void g() {
extern void f(int);
f("asdf"); // error: f(int) hides f(const char*)
// so there is no f(const char*) in this scope
}
void caller () {
extern void callee(int, int);
{
extern void callee(int); // hides callee(int, int)
callee(88, 99); // error: only callee(int) in scope
}
}
class T {
public:
T();
};
class C : T {
public:
C(int);
};
T a = 1; // ill-formed: T(C(1)) not tried
postfix-expression ( expression-list )if the postfix-expression denotes a set of overloaded functions and/or function templates, overload resolution is applied as specified in [over.call.func].
postfix-expression: postfix-expression . id-expression postfix-expression -> id-expression primary-expressionThese represent two syntactic subcategories of function calls: qualified function calls and unqualified function calls.
operator conversion-type-id ( ) cv-qualifier ref-qualifier noexcept-specifier attribute-specifier-seq ;where cv-qualifier is the same cv-qualification as, or a greater cv-qualification than, cv, and where conversion-type-id denotes the type “pointer to function of () returning R”, or the type “reference to pointer to function of () returning R”, or the type “reference to function of () returning R”, a surrogate call function with the unique name call-function and having the form
R call-function ( conversion-type-id F, P a, …, P a) { return F (a, …, a); }is also considered as a candidate function.
int f1(int);
int f2(float);
typedef int (*fp1)(int);
typedef int (*fp2)(float);
struct A {
operator fp1() { return f1; }
operator fp2() { return f2; }
} a;
int i = a(1); // calls f1 via pointer returned from conversion function
struct String {
String (const String&);
String (const char*);
operator const char* ();
};
String operator + (const String&, const String&);
void f() {
const char* p= "one" + "two"; // ill-formed because neither operand has class or enumeration type
int I = 1 + 1; // always evaluates to 2 even if class or enumeration types exist
// that would perform the operation.
}
Subclause | Expression | As member function | As non-member function |
@a | (a).operator@ ( ) | operator@(a) | |
a@b | (a).operator@ (b) | operator@(a, b) | |
a=b | (a).operator= (b) | ||
a[b] | (a).operator[](b) | ||
a-> | (a).operator->( ) | ||
a@ | (a).operator@ (0) | operator@(a, 0) |
struct A {
operator int();
};
A operator+(const A&, const A&);
void m() {
A a, b;
a + b; // operator+(a, b) chosen over int(a) + int(b)
}
struct X {
operator double();
};
struct Y {
operator int*();
};
int *a = Y() + 100.0; // error: pointer arithmetic requires integral operand
int *b = Y() + X(); // error: pointer arithmetic requires integral operand
struct A { };
void operator + (A, A);
struct B {
void operator + (B);
void f ();
};
A a;
void B::f() {
operator+ (a,a); // error: global operator hidden by member
a + a; // OK: calls global operator+
}
template <class T> struct A {
explicit A(const T&, ...) noexcept; // #1
A(T&&, ...); // #2
};
int i;
A a1 = { i, i }; // error: explicit constructor #1 selected in copy-list-initialization during deduction,
// cannot deduce from non-forwarding rvalue reference in #2
A a2{i, i}; // OK, #1 deduces to A<int> and also initializes
A a3{0, i}; // OK, #2 deduces to A<int> and also initializes
A a4 = {0, i}; // OK, #2 deduces to A<int> and also initializes
template <class T> A(const T&, const T&) -> A<T&>; // #3
template <class T> explicit A(T&&, T&&) -> A<T>; // #4
A a5 = {0, 1}; // error: explicit deduction guide #4 selected in copy-list-initialization during deduction
A a6{0,1}; // OK, #4 deduces to A<int> and #2 initializes
A a7 = {0, i}; // error: #3 deduces to A<int&>, #1 and #2 declare same constructor
A a8{0,i}; // error: #3 deduces to A<int&>, #1 and #2 declare same constructor
template <class T> struct B {
template <class U> using TA = T;
template <class U> B(U, TA<U>);
};
B b{(int*)0, (char*)0}; // OK, deduces B<char*>
struct A {
A();
operator int();
operator double();
} a;
int i = a; // a.operator int() followed by no conversion is better than
// a.operator double() followed by a conversion to int
float x = a; // ambiguous: both possibilities require conversions,
// and neither is better than the other
template <class T> struct A {
operator T&(); // #1
operator T&&(); // #2
};
typedef int Fn();
A<Fn> a;
Fn& lf = a; // calls #1
Fn&& rf = a; // calls #2
template <class T> struct A {
using value_type = T;
A(value_type); // #1
A(const A&); // #2
A(T, T, int); // #3
template<class U>
A(int, T, U); // #4
// #5 is the copy deduction candidate, A(A)
};
A x(1, 2, 3); // uses #3, generated from a non-template constructor
template <class T>
A(T) -> A<T>; // #6, less specialized than #5
A a(42); // uses #6 to deduce A<int> and #1 to initialize
A b = a; // uses #5 to deduce A<int> and #2 to initialize
template <class T>
A(A<T>) -> A<A<T>>; // #7, as specialized as #5
A b2 = a; // uses #7 to deduce A<A<int>> and #1 to initialize
void Fcn(const int*, short);
void Fcn(int*, int);
int i;
short s = 0;
void f() {
Fcn(&i, s); // is ambiguous because &i → int* is better than &i → const int*
// but s → short is also better than s → int
Fcn(&i, 1L); // calls Fcn(int*, int), because &i → int* is better than &i → const int*
// and 1L → short and 1L → int are indistinguishable
Fcn(&i, 'c'); // calls Fcn(int*, int), because &i → int* is better than &i → const int*
// and c → int is better than c → short
}
namespace A {
extern "C" void f(int = 5);
}
namespace B {
extern "C" void f(int = 5);
}
using A::f;
using B::f;
void use() {
f(3); // OK, default argument was not used for viability
f(); // Error: found default argument twice
}
struct Y { Y(int); };
struct A { operator int(); };
Y y1 = A(); // error: A::operator int() is not a candidate
struct X { };
struct B { operator X(); };
B b;
X x({b}); // error: B::operator X() is not a candidate
class B;
class A { A (B&);};
class B { operator A (); };
class C { C (B&); };
void f(A) { }
void f(C) { }
B b;
f(b); // ill-formed: ambiguous because there is a conversion b → C (via constructor)
// and an (ambiguous) conversion b → A (via constructor or conversion function)
void f(B) { }
f(b); // OK, unambiguous
Conversion | Category | Rank | Subclause |
No conversions required | Identity | ||
Lvalue-to-rvalue conversion | |||
Array-to-pointer conversion | Lvalue Transformation | ||
Function-to-pointer conversion | Exact Match | ||
Qualification conversions | |||
Function pointer conversion | Qualification Adjustment | ||
Integral promotions | |||
Floating-point promotion | Promotion | Promotion | |
Integral conversions | |||
Floating-point conversions | |||
Floating-integral conversions | |||
Pointer conversions | Conversion | Conversion | |
Pointer to member conversions | |||
Boolean conversions |
struct A {};
struct B : public A {} b;
int f(A&);
int f(B&);
int i = f(b); // calls f(B&), an exact match, rather than f(A&), a conversion
void f(std::initializer_list<int>);
f( {} ); // OK: f(initializer_list<int>) identity conversion
f( {1,2,3} ); // OK: f(initializer_list<int>) identity conversion
f( {'a','b'} ); // OK: f(initializer_list<int>) integral promotion
f( {1.0} ); // error: narrowing
struct A {
A(std::initializer_list<double>); // #1
A(std::initializer_list<complex<double>>); // #2
A(std::initializer_list<std::string>); // #3
};
A a{ 1.0,2.0 }; // OK, uses #1
void g(A);
g({ "foo", "bar" }); // OK, uses #3
typedef int IA[3];
void h(const IA&);
h({ 1, 2, 3 }); // OK: identity conversion
struct A {
A(std::initializer_list<int>);
};
void f(A);
f( {'a', 'b'} ); // OK: f(A(std::initializer_list<int>)) user-defined conversion
struct B {
B(int, double);
};
void g(B);
g( {'a', 'b'} ); // OK: g(B(int, double)) user-defined conversion
g( {1.0, 1.0} ); // error: narrowing
void f(B);
f( {'a', 'b'} ); // error: ambiguous f(A) or f(B)
struct C {
C(std::string);
};
void h(C);
h({"foo"}); // OK: h(C(std::string("foo")))
struct D {
D(A, C);
};
void i(D);
i({ {1,2}, {"bar"} }); // OK: i(D(A(std::initializer_list<int>{1,2}), C(std::string("bar"))))
struct A {
int m1;
double m2;
};
void f(A);
f( {'a', 'b'} ); // OK: f(A(int,double)) user-defined conversion
f( {1.0} ); // error: narrowing
struct A {
int m1;
double m2;
};
void f(const A&);
f( {'a', 'b'} ); // OK: f(A(int,double)) user-defined conversion
f( {1.0} ); // error: narrowing
void g(const double &);
g({1}); // same conversion as int to double
void f(int);
f( {'a'} ); // OK: same conversion as char to int
f( {1.0} ); // error: narrowing
void f1(int); // #1 void f1(std::initializer_list<long>); // #2 void g1() { f1({42}); } // chooses #2 void f2(std::pair<const char*, const char*>); // #3 void f2(std::initializer_list<std::string>); // #4 void g2() { f2({"foo","bar"}); } // chooses #4
int i; int f1(); int&& f2(); int g(const int&); int g(const int&&); int j = g(i); // calls g(const int&) int k = g(f1()); // calls g(const int&&) int l = g(f2()); // calls g(const int&&) struct A { A& operator<<(int); void p() &; void p() &&; }; A& operator<<(A&&, char); A() << 1; // calls A::operator<<(int) A() << 'c'; // calls operator<<(A&&, char) A a; a << 1; // calls A::operator<<(int) a << 'c'; // calls A::operator<<(int) A().p(); // calls A::p()&& a.p(); // calls A::p()&
int f(void(&)()); // #1 int f(void(&&)()); // #2 void g(); int i1 = f(g); // calls #1
int f(const volatile int *);
int f(const int *);
int i;
int j = f(&i); // calls f(const int*)
int f(const int &); int f(int &); int g(const int &); int g(int); int i; int j = f(i); // calls f(int &) int k = g(i); // ambiguous struct X { void f() const; void f(); }; void g(const X& a, X b) { a.f(); // calls X::f() const b.f(); // calls X::f() }
struct A {
operator short();
} a;
int f(int);
int f(float);
int i = f(a); // calls f(int), because short → int is
// better than short → float.
struct A {};
struct B : public A {};
struct C : public B {};
C* pc;
int f(A*);
int f(B*);
int i = f(pc); // calls f(B*)
int f(double); int f(int); int (*pfd)(double) = &f; // selects f(double) int (*pfi)(int) = &f; // selects f(int) int (*pfe)(...) = &f; // error: type mismatch int (&rfi)(int) = f; // selects f(int) int (&rfd)(double) = f; // selects f(double) void g() { (int (*)(int))&f; // cast expression as selector }
struct X {
int f(int);
static int f(long);
};
int (X::*p1)(int) = &X::f; // OK
int (*p2)(int) = &X::f; // error: mismatch
int (*p3)(long) = &X::f; // OK
int (X::*p4)(long) = &X::f; // error: mismatch
int (X::*p5)(int) = &(X::f); // error: wrong syntax for
// pointer to member
int (*p6)(long) = &(X::f); // OK
operator-function-id: operator operator
operator: one of new delete new[] delete[] + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || ++ -- , ->* -> ( ) [ ]
. .* :: ?:
complex z = a.operator+(b); // complex z = a+b;
void* p = operator new(sizeof(int)*n);
struct B {
virtual int operator= (int);
virtual B& operator= (const B&);
};
struct D : B {
virtual int operator= (int);
virtual D& operator= (const B&);
};
D dobj1;
D dobj2;
B* bptr = &dobj1;
void f() {
bptr->operator=(99); // calls D::operator=(int)
*bptr = 99; // ditto
bptr->operator=(dobj2); // calls D::operator=(const B&)
*bptr = dobj2; // ditto
dobj1 = dobj2; // calls implicitly-declared D::operator=(const D&)
}postfix-expression ( expression-list )where the postfix-expression evaluates to a class object and the possibly empty expression-list matches the parameter list of an operator() member function of the class.
postfix-expression [ expr-or-braced-init-list ]Thus, a subscripting expression x[y] is interpreted as x.operator[](y) for a class object x of type T if T::operator[](T1) exists and if the operator is selected as the best match function by the overload resolution mechanism ([over.match.best]).
struct X {
Z operator[](std::initializer_list<int>);
};
X x;
x[{1,2,3}] = 7; // OK: meaning x.operator[]({1,2,3})
int a[10];
a[{1,2,3}] = 7; // error: built-in subscript operator
postfix-expression -> template id-expression postfix-expression -> pseudo-destructor-nameAn expression x->m is interpreted as (x.operator->())->m for a class object x of type T if T::operator->() exists and if the operator is selected as the best match function by the overload resolution mechanism ([over.match]).
struct X {
X& operator++(); // prefix ++a
X operator++(int); // postfix a++
};
struct Y { };
Y& operator++(Y&); // prefix ++b
Y operator++(Y&, int); // postfix b++
void f(X a, Y b) {
++a; // a.operator++();
a++; // a.operator++(0);
++b; // operator++(b);
b++; // operator++(b, 0);
a.operator++(); // explicit call: like ++a;
a.operator++(0); // explicit call: like a++;
operator++(b); // explicit call: like ++b;
operator++(b, 0); // explicit call: like b++;
}const char* unsigned long long int long double char wchar_t char16_t char32_t const char*, std::size_t const wchar_t*, std::size_t const char16_t*, std::size_t const char32_t*, std::size_t
void operator "" _km(long double); // OK string operator "" _i18n(const char*, std::size_t); // OK template <char...> double operator "" _\u03C0(); // OK: UCN for lowercase pi float operator ""_e(const char*); // OK float operator ""E(const char*); // error: reserved literal suffix ([usrlit.suffix], [lex.ext]) double operator""_Bq(long double); // OK: does not use the reserved identifier _Bq ([lex.name]) double operator"" _Bq(long double); // uses the reserved identifier _Bq ([lex.name]) float operator " " B(const char*); // error: non-empty string-literal string operator "" 5X(const char*, std::size_t); // error: invalid literal suffix identifier double operator "" _miles(double); // error: invalid parameter-declaration-clause template <char...> int operator "" _j(const char*); // error: invalid parameter-declaration-clause extern "C" void operator "" _m(long double); // error: C language linkage
vq T& operator++(vq T&); T operator++(vq T&, int);
vq T& operator--(vq T&); T operator--(vq T&, int);
T*vq& operator++(T*vq&); T*vq& operator--(T*vq&); T* operator++(T*vq&, int); T* operator--(T*vq&, int);
T& operator*(T*);
T& operator*(T*);
T operator+(T); T operator-(T);
T operator~(T);
cv12 T& operator->*(cv1 C1*, cv2 T C2::*);
LR operator*(L, R); LR operator/(L, R); LR operator+(L, R); LR operator-(L, R); bool operator<(L, R); bool operator>(L, R); bool operator<=(L, R); bool operator>=(L, R); bool operator==(L, R); bool operator!=(L, R);
T* operator+(T*, std::ptrdiff_t); T& operator[](T*, std::ptrdiff_t); T* operator-(T*, std::ptrdiff_t); T* operator+(std::ptrdiff_t, T*); T& operator[](std::ptrdiff_t, T*);
std::ptrdiff_t operator-(T, T);
bool operator<(T, T); bool operator>(T, T); bool operator<=(T, T); bool operator>=(T, T); bool operator==(T, T); bool operator!=(T, T);
bool operator==(T, T); bool operator!=(T, T);
LR operator%(L, R); LR operator&(L, R); LR operator^(L, R); LR operator|(L, R); L operator<<(L, R); L operator>>(L, R);
vq L& operator=(vq L&, R); vq L& operator*=(vq L&, R); vq L& operator/=(vq L&, R); vq L& operator+=(vq L&, R); vq L& operator-=(vq L&, R);
T*vq& operator=(T*vq&, T*);
vq T& operator=(vq T&, T);
T*vq& operator+=(T*vq&, std::ptrdiff_t); T*vq& operator-=(T*vq&, std::ptrdiff_t);
vq L& operator%=(vq L&, R); vq L& operator<<=(vq L&, R); vq L& operator>>=(vq L&, R); vq L& operator&=(vq L&, R); vq L& operator^=(vq L&, R); vq L& operator|=(vq L&, R);
bool operator!(bool); bool operator&&(bool, bool); bool operator||(bool, bool);
LR operator?:(bool, L, R);
template-declaration: template < template-parameter-list > declaration
template-parameter-list: template-parameter template-parameter-list , template-parameter
template<class T>
constexpr T pi = T(3.1415926535897932385L);
template<class T>
T circular_area(T r) {
return pi<T> * r * r;
}
struct matrix_constants {
template<class T>
using pauli = hermitian_matrix<T, 2>;
template<class T>
constexpr pauli<T> sigma1 = { { 0, 1 }, { 1, 0 } };
template<class T>
constexpr pauli<T> sigma2 = { { 0, -1i }, { 1i, 0 } };
template<class T>
constexpr pauli<T> sigma3 = { { 1, 0 }, { 0, -1 } };
};template-parameter: type-parameter parameter-declaration
type-parameter: type-parameter-key ... identifier type-parameter-key identifier = type-id template < template-parameter-list > type-parameter-key ... identifier template < template-parameter-list > type-parameter-key identifier = id-expression
type-parameter-key: class typename
class T { /* ... */ };
int i;
template<class T, T i> void f(T t) {
T t1 = i; // template-parameters T and i
::T t2 = ::i; // global namespace members T and i
}
template<const X& x, int i> void f() {
i++; // error: change of template-parameter value
&x; // OK
&i; // error: address of non-reference template-parameter
int& ri = i; // error: non-const reference bound to temporary
const int& cri = i; // OK: const reference bound to temporary
}template<double d> class X; // error template<double* pd> class Y; // OK template<double& rd> class Z; // OK
template<int* a> struct R { /* ... */ };
template<int b[5]> struct S { /* ... */ };
int p;
R<&p> w; // OK
S<&p> x; // OK due to parameter adjustment
int v[5];
R<v> y; // OK due to implicit argument conversion
S<v> z; // OK due to both adjustment and conversion
template<class T1, class T2 = int> class A; template<class T1 = int, class T2> class A;
template<class T1 = int, class T2 = int> class A;
template<class T1 = int, class T2> class B; // error // U can be neither deduced from the parameter-type-list nor specified template<class... T, class... U> void f() { } // error template<class... T, class U> void g() { } // error
template<class T = int> class X;
template<class T = int> class X { /* ... */ }; // error
template<int i = 3 > 4 > // syntax error class X { /* ... */ }; template<int i = (3 > 4) > // OK class Y { /* ... */ };
template <class T = float> struct B {};
template <template <class TT = float> class T> struct A {
inline void f();
inline void g();
};
template <template <class TT> class T> void A<T>::f() {
T<> t; // error - TT has no default template argument
}
template <template <class TT = char> class T> void A<T>::g() {
T<> t; // OK - T<char>
}template <class... Types> class Tuple; // Types is a template type parameter pack // but not a pack expansion template <class T, int... Dims> struct multi_array; // Dims is a non-type template parameter pack // but not a pack expansion template<class... T> struct value_holder { template<T... Values> struct apply { }; // Values is a non-type template parameter pack // and a pack expansion }; template<class... T, T... Values> struct static_array;// error: Values expands template type parameter // pack T within the same template parameter list
simple-template-id: template-name < template-argument-list >
template-id: simple-template-id operator-function-id < template-argument-list > literal-operator-id < template-argument-list >
template-name: identifier
template-argument-list: template-argument ... template-argument-list , template-argument ...
template-argument: constant-expression type-id id-expression
template<int i> class X { /* ... */ };
X< 1>2 > x1; // syntax error
X<(1>2)> x2; // OK
template<class T> class Y { /* ... */ };
Y<X<1>> x3; // OK, same as Y<X<1> > x3;
Y<X<6>>1>> x4; // syntax error
Y<X<(6>>1)>> x5; // OK
struct X {
template<std::size_t> X* alloc();
template<std::size_t> static X* adjust();
};
template<class T> void f(T* p) {
T* p1 = p->alloc<200>(); // ill-formed: < means less than
T* p2 = p->template alloc<200>(); // OK: < starts template argument list
T::adjust<100>(); // ill-formed: < means less than
T::template adjust<100>(); // OK: < starts template argument list
}
template <class T> struct A {
void f(int);
template <class U> void f(U);
};
template <class T> void f(T t) {
A<T> a;
a.template f<>(t); // OK: calls template
a.template f(t); // error: not a template-id
}
template <class T> struct B {
template <class T2> struct C { };
};
// OK: T::template C names a class template:
template <class T, template <class X> class TT = T::template C> struct D { };
D<B<int> > db;
template<class T> class Array {
T* v;
int sz;
public:
explicit Array(int);
T& operator[](int);
T& elem(int i) { return v[i]; }
};
Array<int> v1(20);
typedef std::complex<double> dcomplex; // std::complex is a standard library template
Array<dcomplex> v2(30);
Array<dcomplex> v3(40);
void bar() {
v1[3] = 7;
v2[3] = v3.elem(4) = dcomplex(7,8);
}
template<class T> void f();
template<int I> void f();
void g() {
f<int()>(); // int() is a type-id: call the first f()
}
template<class T> class X {
static T t;
};
class Y {
private:
struct S { /* ... */ };
X<S> x; // OK: S is accessible
// X<Y::S> has a static member of type Y::S
// OK: even though Y::S is private
};
X<Y::S> y; // error: S not accessible
template <template <class TT> class T> class A {
typename T<int>::S s;
};
template <class U> class B {
private:
struct S { /* ... */ };
};
A<B> b; // ill-formed: A has no access to B::S
template<class T = char> class String; String<>* p; // OK: String<char> String* q; // syntax error template<class ... Elements> class Tuple; Tuple<>* t; // OK: Elements is empty Tuple* u; // syntax error
template<class T> struct A {
~A();
};
void f(A<int>* p, A<int>* q) {
p->A<int>::~A(); // OK: destructor call
q->A<int>::~A<int>(); // OK: destructor call
}
template <class T> class X { };
template <class T> void f(T t) { }
struct { } unnamed_obj;
void f() {
struct A { };
enum { e1 };
typedef struct { } B;
B b;
X<A> x1; // OK
X<A*> x2; // OK
X<B> x3; // OK
f(e1); // OK
f(unnamed_obj); // OK
f(b); // OK
}
template<const int* pci> struct X { /* ... */ };
int ai[10];
X<ai> xi; // array to pointer and qualification conversions
struct Y { /* ... */ };
template<const Y& b> struct Z { /* ... */ };
Y y;
Z<y> z; // no conversion, but note extra cv-qualification
template<int (&pa)[5]> struct W { /* ... */ };
int b[5];
W<b> w; // no conversion
void f(char);
void f(int);
template<void (*pf)(int)> struct A { /* ... */ };
A<&f> a; // selects f(int)
template<auto n> struct B { /* ... */ };
B<5> b1; // OK: template parameter type is int
B<'a'> b2; // OK: template parameter type is char
B<2.5> b3; // error: template parameter type cannot be double
template<int* p> class X { };
int a[10];
struct S { int m; static int s; } s;
X<&a[2]> x3; // error: address of array element
X<&s.m> x4; // error: address of non-static member
X<&s.s> x5; // OK: address of static member
X<&S::s> x6; // OK: address of static member
template<const int& CRI> struct B { /* ... */ };
B<1> b2; // error: temporary would be required for template argument
int c = 1;
B<c> b1; // OK
template<class T> class A { // primary template
int x;
};
template<class T> class A<T*> { // partial specialization
long x;
};
template<template<class U> class V> class C {
V<int> y;
V<int*> z;
};
C<A> c; // V<int> within C<A> uses the primary template, so c.y.x has type int
// V<int*> within C<A> uses the partial specialization, so c.z.x has type long
template<class T> class A { /* ... */ };
template<class T, class U = T> class B { /* ... */ };
template<class ... Types> class C { /* ... */ };
template<auto n> class D { /* ... */ };
template<template<class> class P> class X { /* ... */ };
template<template<class ...> class Q> class Y { /* ... */ };
template<template<int> class R> class Z { /* ... */ };
X<A> xa; // OK
X<B> xb; // OK
X<C> xc; // OK
Y<A> ya; // OK
Y<B> yb; // OK
Y<C> yc; // OK
Z<D> zd; // OK
template <class T> struct eval;
template <template <class, class...> class TT, class T1, class... Rest>
struct eval<TT<T1, Rest...>> { };
template <class T1> struct A;
template <class T1, class T2> struct B;
template <int N> struct C;
template <class T1, int N> struct D;
template <class T1, class T2, int N = 17> struct E;
eval<A<int>> eA; // OK: matches partial specialization of eval
eval<B<int, float>> eB; // OK: matches partial specialization of eval
eval<C<17>> eC; // error: C does not match TT in partial specialization
eval<D<int, 17>> eD; // error: D does not match TT in partial specialization
eval<E<int, float>> eE; // error: E does not match TT in partial specialization
template<class E, int size> class buffer { /* ... */ };
buffer<char,2*512> x;
buffer<char,1024> y;
template<class T, void(*err_fct)()> class list { /* ... */ };
list<int,&error_handler1> x1;
list<int,&error_handler2> x2;
list<int,&error_handler2> x3;
list<char,&error_handler2> x4;
template<class T> struct X { };
template<class> struct Y { };
template<class T> using Z = Y<T>;
X<Y<int> > y;
X<Z<int> > z;
template<class T1, class T2, int I> class A<T1, T2, I> { }; // error
template<class T1, int I> void sort<T1, I>(T1 data[I]); // error
template<class T> class Array {
T* v;
int sz;
public:
explicit Array(int);
T& operator[](int);
T& elem(int i) { return v[i]; }
};
The prefix template<class T>
specifies that a template is being declared and that a
type-name
T
may be used in the declaration.
template<class T1, class T2> struct A {
void f1();
void f2();
};
template<class T2, class T1> void A<T2,T1>::f1() { } // OK
template<class T2, class T1> void A<T1,T2>::f2() { } // error
template<class ... Types> struct B {
void f3();
void f4();
};
template<class ... Types> void B<Types ...>::f3() { } // OK
template<class ... Types> void B<Types>::f4() { } // error
template<class T> class Array {
T* v;
int sz;
public:
explicit Array(int);
T& operator[](int);
T& elem(int i) { return v[i]; }
};
template<class T> T& Array<T>::operator[](int i) {
if (i<0 || sz<=i) error("Array: range error");
return v[i];
}
template<class T> struct A {
class B;
};
A<int>::B* b1; // OK: requires A to be defined but not A::B
template<class T> class A<T>::B { };
A<int>::B b2; // OK: requires A::B to be defined
template<class T> class X {
static T s;
};
template<class T> T X<T>::s = 0;
struct limits {
template<class T>
static const T min; // declaration
};
template<class T>
const T limits::min = { }; // definition
template <class T> struct A {
static int i[];
};
template <class T> int A<T>::i[4]; // 4 elements
template <> int A<int>::i[] = { 1 }; // OK: 1 element
template<class T> struct string {
template<class T2> int compare(const T2&);
template<class T2> string(const string<T2>& s) { /* ... */ }
};
template<class T> template<class T2> int string<T>::compare(const T2& s) {
}
template <class T> struct A {
void f(int);
template <class T2> void f(T2);
};
template <> void A<int>::f(int) { } // non-template member function
template <> template <> void A<int>::f<>(int) { } // member function template specialization
int main() {
A<char> ac;
ac.f(1); // non-template
ac.f('c'); // template
ac.f<>(1); // template
}
template <class T> struct AA {
template <class C> virtual void g(C); // error
virtual void f(); // OK
};
class B {
virtual void f(int);
};
class D : public B {
template <class T> void f(T); // does not override B::f(int)
void f(int i) { f<>(i); } // overriding function that calls the template instantiation
};
struct A {
template <class T> operator T*();
};
template <class T> A::operator T*(){ return 0; }
template <> A::operator char*(){ return 0; } // specialization
template A::operator void*(); // explicit instantiation
int main() {
A a;
int* ip;
ip = a.operator int*(); // explicit call to template operator A::operator int*()
}
template<class ... Types> struct Tuple { };
Tuple<> t0; // Types contains no arguments
Tuple<int> t1; // Types contains one argument: int
Tuple<int, float> t2; // Types contains two arguments: int and float
Tuple<0> error; // error: 0 is not a type
template<class ... Types> void f(Types ... args); f(); // OK: args contains no arguments f(1); // OK: args contains one argument: int f(2, 1.0); // OK: args contains two arguments: int and double
template<class ... Types> void f(Types ... rest);
template<class ... Types> void g(Types ... rest) {
f(&rest ...); // “&rest ...” is a pack expansion; “&rest” is its pattern
}
template<typename...> struct Tuple {};
template<typename T1, typename T2> struct Pair {};
template<class ... Args1> struct zip {
template<class ... Args2> struct with {
typedef Tuple<Pair<Args1, Args2> ... > type;
};
};
typedef zip<short, int>::with<unsigned short, unsigned>::type T1;
// T1 is Tuple<Pair<short, unsigned short>, Pair<int, unsigned>>
typedef zip<short>::with<unsigned short, unsigned>::type T2;
// error: different number of arguments specified for Args1 and Args2
template<class ... Args>
void g(Args ... args) { // OK: Args is expanded by the function parameter pack args
f(const_cast<const Args*>(&args)...); // OK: “Args” and “args” are expanded
f(5 ...); // error: pattern does not contain any parameter packs
f(args); // error: parameter pack “args” is not expanded
f(h(args ...) + args ...); // OK: first “args” expanded within h,
// second “args” expanded within f
}
template<class... T> struct X : T... { };
template<class... T> void f(T... values) {
X<T...> x(values...);
}
template void f<>(); // OK: X<> has no base classes
// x is a variable of type X<> that is value-initialized
Operator | Value when parameter pack is empty |
&& | true |
|| | false |
, | void() |
template<class T> class task;
template<class T> task<T>* preempt(task<T>*);
template<class T> class task {
friend void next_time();
friend void process(task<T>*);
friend task<T>* preempt<T>(task<T>*);
template<class C> friend int func(C);
friend class task<int>;
template<class P> friend class frd;
};
class A {
template<class T> friend class B; // OK
template<class T> friend void f(T){ /* ... */ } // OK
};
class X {
template<class T> friend struct A;
class Y { };
};
template<class T> struct A { X::Y ab; }; // OK
template<class T> struct A<T*> { X::Y ab; }; // OK
template<class T> struct A {
struct B { };
void f();
struct D {
void g();
};
};
template<> struct A<int> {
struct B { };
int f();
struct D {
void g();
};
};
class C {
template<class T> friend struct A<T>::B; // grants friendship to A<int>::B even though
// it is not a specialization of A<T>::B
template<class T> friend void A<T>::f(); // does not grant friendship to A<int>::f()
// because its return type does not match
template<class T> friend void A<T>::D::g(); // does not grant friendship to A<int>::D::g()
// because A<int>::D is not a specialization of A<T>::D
};
template<class T1, class T2, int I> class A { };
template<class T, int I> class A<T, T*, I> { };
template<class T1, class T2, int I> class A<T1*, T2, I> { };
template<class T> class A<int, T*, 5> { };
template<class T1, class T2, int I> class A<T1, T2*, I> { };
template<class T> struct A {
struct C {
template<class T2> struct B { };
template<class T2> struct B<T2**> { }; // partial specialization #1
};
};
// partial specialization of A<T>::C::B<T2>
template<class T> template<class T2>
struct A<T>::C::B<T2*> { }; // #2
A<short>::C::B<int*> absip; // uses partial specialization #2
namespace N {
template<class T1, class T2> class A { }; // primary template
}
using N::A; // refers to the primary template
namespace N {
template<class T> class A<T, T*> { }; // partial specialization
}
A<int,int*> a; // uses the partial specialization, which is found through the using-declaration
// which refers to the primary template
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error
template<class T1, class T2, int I> class A { }; // #1
template<class T, int I> class A<T, T*, I> { }; // #2
template<class T1, class T2, int I> class A<T1*, T2, I> { }; // #3
template<class T> class A<int, T*, 5> { }; // #4
template<class T1, class T2, int I> class A<T1, T2*, I> { }; // #5
A<int, int, 1> a1; // uses #1
A<int, int*, 1> a2; // uses #2, T is int, I is 1
A<int, char*, 5> a3; // uses #4, T is char
A<int, char*, 1> a4; // uses #5, T1 is int, T2 is char, I is 1
A<int*, int*, 2> a5; // ambiguous: matches #3 and #5
template <int I, int J> struct A {};
template <int I> struct A<I+5, I*2> {}; // error
template <int I> struct A<I, I> {}; // OK
template <int I, int J, int K> struct B {};
template <int I> struct B<I, I*2, 2> {}; // OK
template<int I, int J, class T> class X { };
template<int I, int J> class X<I, J, int> { }; // #1
template<int I> class X<I, I, int> { }; // #2
template<int I0, int J0> void f(X<I0, J0, int>); // A
template<int I0> void f(X<I0, I0, int>); // B
template <auto v> class Y { };
template <auto* p> class Y<p> { }; // #3
template <auto** pp> class Y<pp> { }; // #4
template <auto* p0> void g(Y<p0>); // C
template <auto** pp0> void g(Y<pp0>); // D
// primary class template template<class T, int I> struct A { void f(); }; // member of primary class template template<class T, int I> void A<T,I>::f() { } // class template partial specialization template<class T> struct A<T,2> { void f(); void g(); void h(); }; // member of class template partial specialization template<class T> void A<T,2>::g() { } // explicit specialization template<> void A<char,2>::h() { } int main() { A<char,0> a0; A<char,2> a2; a0.f(); // OK, uses definition of primary template's member a2.g(); // OK, uses definition of partial specialization's member a2.h(); // OK, uses definition of explicit specialization's member a2.f(); // ill-formed, no definition of f for A<T,2>; the primary template is not used here }
template<class T> struct A {
template<class T2> struct B {}; // #1
template<class T2> struct B<T2*> {}; // #2
};
template<> template<class T2> struct A<short>::B {}; // #3
A<char>::B<int*> abcip; // uses #2
A<short>::B<int*> absip; // uses #3
A<char>::B<int> abci; // uses #1
template<class T> class Array { };
template<class T> void sort(Array<T>&);// translation unit 1: template<class T> void f(T*); void g(int* p) { f(p); // calls f<int>(int*) }
// translation unit 2: template<class T> void f(T); void h(int* p) { f(p); // calls f<int*>(int*) }
template<class T> void f(); template<int I> void f(); // OK: overloads the first template // distinguishable with an explicit template argument list
template <int I, int J> A<I+J> f(A<I>, A<J>); // #1 template <int K, int L> A<K+L> f(A<K>, A<L>); // same as #1 template <int I, int J> A<I-J> f(A<I>, A<J>); // different from #1
template <int I, int J> void f(A<I+J>); // #1 template <int K, int L> void f(A<K+L>); // same as #1 template <class T> decltype(g(T())) h(); int g(int); template <class T> decltype(g(T())) h() // redeclaration of h() uses the earlier lookup { return g(T()); } // ...although the lookup here does find g(int) int i = h<int>(); // template argument substitution fails; g(int) // was not in scope at the first declaration of h()
// Guaranteed to be the same template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+10>); // Guaranteed to be different template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+11>); // Ill-formed, no diagnostic required template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+1+2+3+4>);
struct A { };
template<class T> struct B {
template<class R> int operator*(R&); // #1
};
template<class T, class R> int operator*(T&, R&); // #2
// The declaration of B::operator* is transformed into the equivalent of
// template<class R> int operator*(B<A>&, R&); // #1a
int main() {
A a;
B<A> b;
b * a; // calls #1a
}
template<class T> struct A { A(); };
template<class T> void f(T);
template<class T> void f(T*);
template<class T> void f(const T*);
template<class T> void g(T);
template<class T> void g(T&);
template<class T> void h(const T&);
template<class T> void h(A<T>&);
void m() {
const int* p;
f(p); // f(const T*) is more specialized than f(T) or f(T*)
float x;
g(x); // ambiguous: g(T) or g(T&)
A<int> z;
h(z); // overload resolution selects h(A<T>&)
const A<int> z2;
h(z2); // h(const T&) is called because h(A<T>&) is not callable
}template<class T> void f(T); // #1 template<class T> void f(T*, int=1); // #2 template<class T> void g(T); // #3 template<class T> void g(T*, ...); // #4
int main() {
int* ip;
f(ip); // calls #2
g(ip); // calls #4
}
template<class T, class U> struct A { };
template<class T, class U> void f(U, A<U, T>* p = 0); // #1
template< class U> void f(U, A<U, U>* p = 0); // #2
template<class T > void g(T, T = T()); // #3
template<class T, class... U> void g(T, U ...); // #4
void h() {
f<int>(42, (A<int, int>*)0); // calls #2
f<int>(42); // error: ambiguous
g(42); // error: ambiguous
}template<class T, class... U> void f(T, U...); // #1 template<class T > void f(T); // #2 template<class T, class... U> void g(T*, U...); // #3 template<class T > void g(T); // #4 void h(int i) { f(&i); // error: ambiguous g(&i); // OK: calls #3 }
template<class T> struct Alloc { /* ... */ };
template<class T> using Vec = vector<T, Alloc<T>>;
Vec<int> v; // same as vector<int, Alloc<int>> v;
template<class T>
void process(Vec<T>& v)
{ /* ... */ }
template<class T>
void process(vector<T, Alloc<T>>& w)
{ /* ... */ } // error: redefinition
template<template<class> class TT>
void f(TT<int>);
f(v); // error: Vec not deduced
template<template<class,class> class TT>
void g(TT<int, Alloc<int>>);
g(v); // OK: TT = vector
template<typename...> using void_t = void;
template<typename T> void_t<typename T::foo> f();
f<int>(); // error, int does not have a nested type foo
template <class T> struct A;
template <class T> using B = typename A<T>::U;
template <class T> struct A {
typedef B<T> U;
};
B<short> b; // error: instantiation of B<short> uses own type via A<short>::U
// no B declared here class X; template<class T> class Y { class Z; // forward declaration of member class void f() { X* a1; // declare pointer to X T* a2; // declare pointer to T Y* a3; // declare pointer to Y<T> Z* a4; // declare pointer to Z typedef typename T::A TA; TA* a5; // declare pointer to T's A typename T::A* a6; // declare pointer to T's A T::A* a7; // T::A is not a type name: // multiplication of T::A by a7; ill-formed, no visible declaration of a7 B* a8; // B is not a type name: // multiplication of B by a8; ill-formed, no visible declarations of B and a8 } };
typename-specifier: typename nested-name-specifier identifier typename nested-name-specifier template simple-template-id
struct A {
struct X { };
int X;
};
struct B {
struct X { };
};
template<class T> void f(T t) {
typename T::X x;
}
void foo() {
A a;
B b;
f(b); // OK: T::X refers to B::X
f(a); // error: T::X refers to the data member A::X not the struct A::X
}
template <class T> void f(int i) {
T::x * i; // T::x must not be a type
}
struct Foo {
typedef int x;
};
struct Bar {
static int const x = 5;
};
int main() {
f<Bar>(1); // OK
f<Foo>(1); // error: Foo::x is a type
}
template<class T> struct A {
typedef int B;
B b; // OK, no typename required
};
int j;
template<class T> class X {
void f(T t, int i, char* p) {
t = i; // diagnosed if X::f is instantiated, and the assignment to t is an error
p = i; // may be diagnosed even if X::f is not instantiated
p = j; // may be diagnosed even if X::f is not instantiated
}
void g(T t) {
+; // may be diagnosed even if X::g is not instantiated
}
};
template<class... T> struct A {
void operator++(int, T... t); // error: too many parameters
};
template<class... T> union X : T... { }; // error: union with base class
template<class... T> struct A : T..., T... { }; // error: duplicate base class
#include <iostream>
using namespace std;
template<class T> class Set {
T* p;
int cnt;
public:
Set();
Set<T>(const Set<T>&);
void printall() {
for (int i = 0; i<cnt; i++)
cout << p[i] << '\n';
}
};
void f(char);
template<class T> void g(T t) {
f(1); // f(char)
f(T(1)); // dependent
f(t); // dependent
dd++; // not dependent; error: declaration for dd not found
}
enum E { e };
void f(E);
double dd;
void h() {
g(e); // will cause one call of f(char) followed by two calls of f(E)
g('a'); // will cause three calls of f(char)
}
template<template<class> class T> class A { };
template<class T> class Y;
template<> class Y<int> {
Y* p; // meaning Y<int>
Y<char>* q; // meaning Y<char>
A<Y>* a; // meaning A<::Y>
class B {
template<class> friend class Y; // meaning ::Y
};
};
template <class T> struct Base {
Base* p;
};
template <class T> struct Derived: public Base<T> {
typename Derived::Base* p; // meaning Derived::Base<T>
};
template<class T, template<class> class U = T::template Base> struct Third { };
Third<Base<int> > t; // OK: default argument uses injected-class-name as a template
template <class T> struct Base { };
template <class T> struct Derived: Base<int>, Base<char> {
typename Derived::Base b; // error: ambiguous
typename Derived::Base<double> d; // OK
};
template<class T> class X {
X* p; // meaning X<T>
X<T>* p2;
X<int>* p3;
::X* p4; // error: missing template argument list
// ::X does not refer to the injected-class-name
};
template<class T, int i> class Y {
int T; // error: template-parameter redeclared
void f() {
char T; // error: template-parameter redeclared
}
};
template<class X> class X; // error: template-parameter redeclared
template<class T> struct A {
struct B { /* ... */ };
typedef void C;
void f();
template<class U> void g(U);
};
template<class B> void A<B>::f() {
B b; // A's B, not the template parameter
}
template<class B> template<class C> void A<B>::g(C) {
B b; // A's B, not the template parameter
C c; // the template parameter C, not A's C
}
namespace N {
class C { };
template<class T> class B {
void f(T);
};
}
template<class C> void N::B<C>::f(C) {
C b; // C is the template parameter, not N::C
}
struct A {
struct B { /* ... */ };
int a;
int Y;
};
template<class B, class a> struct X : A {
B b; // A's B
a b; // error: A's a isn't a type name
};postfix-expression ( expression-list )where the postfix-expression is an unqualified-id, the unqualified-id denotes a dependent name if
typedef double A;
template<class T> class B {
typedef int A;
};
template<class T> struct X : B<T> {
A a; // a has type double
};
struct A {
struct B { /* ... */ };
int a;
int Y;
};
int a;
template<class T> struct Y : T {
struct B { /* ... */ };
B b; // The B defined in Y
void f(int i) { a = i; } // ::a
Y* p; // Y<T>
};
Y<A> ya;
template <class T> class A {
A* p1; // A is the current instantiation
A<T>* p2; // A<T> is the current instantiation
A<T*> p3; // A<T*> is not the current instantiation
::A<T>* p4; // ::A<T> is the current instantiation
class B {
B* p1; // B is the current instantiation
A<T>::B* p2; // A<T>::B is the current instantiation
typename A<T*>::B* p3; // A<T*>::B is not the current instantiation
};
};
template <class T> class A<T*> {
A<T*>* p1; // A<T*> is the current instantiation
A<T>* p2; // A<T> is not the current instantiation
};
template <class T1, class T2, int I> struct B {
B<T1, T2, I>* b1; // refers to the current instantiation
B<T2, T1, I>* b2; // not the current instantiation
typedef T1 my_T1;
static const int my_I = I;
static const int my_I2 = I+0;
static const int my_I3 = my_I;
B<my_T1, T2, my_I>* b3; // refers to the current instantiation
B<my_T1, T2, my_I2>* b4; // not the current instantiation
B<my_T1, T2, my_I3>* b5; // refers to the current instantiation
};
template<class T> struct A {
typedef int M;
struct B {
typedef void M;
struct C;
};
};
template<class T> struct A<T>::B::C : A<T> {
M m; // OK, A<T>::M
};
template <class T> class A {
static const int i = 5;
int n1[i]; // i refers to a member of the current instantiation
int n2[A::i]; // A::i refers to a member of the current instantiation
int n3[A<T>::i]; // A<T>::i refers to a member of the current instantiation
int f();
};
template <class T> int A<T>::f() {
return i; // i refers to a member of the current instantiation
}
template<class T> class A {
typedef int type;
void f() {
A<T>::type i; // OK: refers to a member of the current instantiation
typename A<T>::other j; // error: neither a member of the current instantiation nor
// a member of an unknown specialization
}
};
struct A {
int m;
};
struct B {
int m;
};
template<typename T>
struct C : A, T {
int f() { return this->m; } // finds A::m in the template definition context
int g() { return m; } // finds A::m in the template definition context
};
template int C<B>::f(); // error: finds both A::m and B::m
template int C<B>::g(); // OK: transformation to class member access syntax
// does not occur in the template definition context; see [class.mfct.non-static]
simple-type-specifier ( expression-list ) :: new new-placement new-type-id new-initializer :: new new-placement ( type-id ) new-initializer dynamic_cast < type-id > ( expression ) static_cast < type-id > ( expression ) const_cast < type-id > ( expression ) reinterpret_cast < type-id > ( expression ) ( type-id ) cast-expression
literal postfix-expression . pseudo-destructor-name postfix-expression -> pseudo-destructor-name sizeof unary-expression sizeof ( type-id ) sizeof ... ( identifier ) alignof ( type-id ) typeid ( expression ) typeid ( type-id ) :: delete cast-expression :: delete [ ] cast-expression throw assignment-expression noexcept ( expression )
sizeof unary-expression sizeof ( type-id ) typeid ( expression ) typeid ( type-id ) alignof ( type-id ) noexcept ( expression )
simple-type-specifier ( expression-list ) static_cast < type-id > ( expression ) const_cast < type-id > ( expression ) reinterpret_cast < type-id > ( expression ) ( type-id ) cast-expression
void g(double);
void h();
template<class T> class Z {
public:
void f() {
g(1); // calls g(double)
h++; // ill-formed: cannot increment function; this could be diagnosed
// either here or at the point of instantiation
}
};
void g(int); // not in scope at the point of the template definition, not considered for the call g(1)
template<typename T> struct number {
number(int);
friend number gcd(number x, number y) { return 0; };
};
void g() {
number<double> a(3), b(4);
a = gcd(a,b); // finds gcd because number<double> is an associated class,
// making gcd visible in its namespace (global scope)
b = gcd(3,4); // ill-formed; gcd is not visible
}
template<class T = int> struct A {
static int x;
};
template<class U> void g(U) { }
template<> struct A<double> { }; // specialize for T == double
template<> struct A<> { }; // specialize for T == int
template<> void g(char) { } // specialize for U == char
// U is deduced from the parameter type
template<> void g<int>(int) { } // specialize for U == int
template<> int A<char>::x = 0; // specialize for T == char
template<class T = int> struct B {
static int x;
};
template<> int B<>::x = 1; // specialize for T == int
template<class T> struct A {
static T t;
};
typedef int function();
A<function> a; // ill-formed: would declare A<function>::t as a static member function
template<class T> class B { /* ... */ };
template<class T> class D : public B<T> { /* ... */ };
void f(void*);
void f(B<int>*);
void g(D<int>* p, D<char>* pp, D<double>* ppp) {
f(p); // instantiation of D<int> required: call f(B<int>*)
B<char>* q = pp; // instantiation of D<char> required: convert D<char>* to B<char>*
delete ppp; // instantiation of D<double> required
}
template<class T, class U>
struct Outer {
template<class X, class Y> struct Inner;
template<class Y> struct Inner<T, Y>; // #1a
template<class Y> struct Inner<T, Y> { }; // #1b; OK: valid redeclaration of #1a
template<class Y> struct Inner<U, Y> { }; // #2
};
Outer<int, int> outer; // error at #2
template<typename T> struct Friendly {
template<typename U> friend int f(U) { return sizeof(T); }
};
Friendly<char> fc;
Friendly<float> ff; // ill-formed: produces second definition of f(U)
template<class T> struct Z {
void f();
void g();
};
void h() {
Z<int> a; // instantiation of class Z<int> required
Z<char>* p; // instantiation of class Z<char> not required
Z<double>* q; // instantiation of class Z<double> not required
a.f(); // instantiation of Z<int>::f() required
p->g(); // instantiation of class Z<char> required, and
// instantiation of Z<char>::g() required
}
template <class T> struct S {
operator int();
};
void f(int);
void f(S<int>&);
void f(S<float>);
void g(S<int>& sr) {
f(sr); // instantiation of S<int> allowed but not required
// instantiation of S<float> allowed but not required
};
namespace N {
template<class T> class List {
public:
T* get();
};
}
template<class K, class V> class Map {
public:
N::List<V> lt;
V get(K);
};
void g(Map<const char*,int>& m) {
int i = m.get("Nicholas");
}
template<class T> void f(T x, T y = ydef(T()), T z = zdef(T()));
class A { };
A zdef(A);
void g(A a, A b, A c) {
f(a, b, c); // no default argument instantiation
f(a, b); // default argument z = zdef(T()) instantiated
f(a); // ill-formed; ydef is not declared
}
template<class T> class X {
X<T>* p; // OK
X<T*> a; // implicit generation of X<T> requires
// the implicit instantiation of X<T*> which requires
// the implicit instantiation of X<T**> which …
};explicit-instantiation: extern template declarationThere are two forms of explicit instantiation: an explicit instantiation definition and an explicit instantiation declaration.
template<class T> class Array { void mf(); };
template class Array<char>;
template void Array<int>::mf();
template<class T> void sort(Array<T>& v) { /* ... */ }
template void sort(Array<char>&); // argument is deduced here
namespace N {
template<class T> void f(T&) { }
}
template void N::f<int>(int&);
namespace N {
template<class T> class Y { void mf() { } };
}
template class Y<int>; // error: class template Y not visible in the global namespace
using N::Y;
template class Y<int>; // error: explicit instantiation outside of the namespace of the template
template class N::Y<char*>; // OK: explicit instantiation in namespace N
template void N::Y<double>::mf(); // OK: explicit instantiation in namespace N
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }
// instantiate sort(Array<int>&) – template-argument deduced
template void sort<>(Array<int>&);explicit-specialization: template < > declaration
template<class T> class stream;
template<> class stream<char> { /* ... */ };
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }
template<> void sort<char*>(Array<char*>&);
template<> class X<int> { /* ... */ }; // error: X not a template
template<class T> class X;
template<> class X<char*> { /* ... */ }; // OK: X is a template
template<class T> struct A {
struct B { };
template<class U> struct C { };
};
template<> struct A<int> {
void f(int);
};
void h() {
A<int> a;
a.f(16); // A<int>::f must be defined somewhere
}
// template<> not used for a member of an explicitly specialized class template
void A<int>::f(int) { /* ... */ }
template<> struct A<char>::B {
void f();
};
// template<> also not used when defining a member of an explicitly specialized member class
void A<char>::B::f() { /* ... */ }
template<> template<class U> struct A<char>::C {
void f();
};
// template<> is used when defining a member of an explicitly specialized member class template
// specialized as a class template
template<>
template<class U> void A<char>::C<U>::f() { /* ... */ }
template<> struct A<short>::B {
void f();
};
template<> void A<short>::B::f() { /* ... */ } // error: template<> not permitted
template<> template<class U> struct A<short>::C {
void f();
};
template<class U> void A<short>::C<U>::f() { /* ... */ } // error: template<> required
class String { };
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }
void f(Array<String>& v) {
sort(v); // use primary template sort(Array<T>&), T is String
}
template<> void sort<String>(Array<String>& v); // error: specialization after use of primary template
template<> void sort<>(Array<char*>& v); // OK: sort<char*> not yet used
template<class T> struct A {
enum E : T;
enum class S : T;
};
template<> enum A<int>::E : int { eint }; // OK
template<> enum class A<int>::S : int { sint }; // OK
template<class T> enum A<T>::E : T { eT };
template<class T> enum class A<T>::S : T { sT };
template<> enum A<char>::E : char { echar }; // ill-formed, A<char>::E was instantiated
// when A<char> was instantiated
template<> enum class A<char>::S : char { schar }; // OK
namespace N {
template<class T> class X { /* ... */ };
template<class T> class Y { /* ... */ };
template<> class X<int> { /* ... */ }; // OK: specialization in same namespace
template<> class Y<double>; // forward-declare intent to specialize for double
}
template<> class N::Y<double> { /* ... */ }; // OK: specialization in enclosing namespace
template<> class N::Y<short> { /* ... */ }; // OK: specialization in enclosing namespace
template<class T> class X; // X is a class template template<> class X<int>; X<int>* p; // OK: pointer to declared class X<int> X<int> x; // error: object of incomplete class X<int>
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v);
// explicit specialization for sort(Array<int>&)
// with deduced template-argument of type int
template<> void sort(Array<int>&);
template<class T> void f(T) { /* ... */ }
template<class T> inline T g(T) { /* ... */ }
template<> inline void f<>(int) { /* ... */ } // OK: inline
template<> int g<>(int) { /* ... */ } // OK: not inline
template<> X Q<int>::x; // declaration template<> X Q<int>::x (); // error: declares a function template<> X Q<int>::x { }; // definition
template<class T> struct A {
void f(T);
template<class X1> void g1(T, X1);
template<class X2> void g2(T, X2);
void h(T) { }
};
// specialization
template<> void A<int>::f(int);
// out of class member template definition
template<class T> template<class X1> void A<T>::g1(T, X1) { }
// member template specialization
template<> template<class X1> void A<int>::g1(int, X1);
// member template specialization
template<> template<>
void A<int>::g1(int, char); // X1 deduced as char
template<> template<>
void A<int>::g2<char>(int, char); // X2 specified as char
// member specialization even if defined in class definition
template<> void A<int>::h(int) { }
template<class T1> class A {
template<class T2> class B {
void mf();
};
};
template<> template<> class A<int>::B<double>;
template<> template<> void A<char>::B<char>::mf();
template <class T1> class A {
template<class T2> class B {
template<class T3> void mf1(T3);
void mf2();
};
};
template <> template <class X>
class A<int>::B {
template <class T> void mf1(T);
};
template <> template <> template<class T>
void A<int>::B<double>::mf1(T t) { }
template <class Y> template <>
void A<Y>::B<double>::mf2() { } // ill-formed; B<double> is specialized but
// its enclosing class template A is not
template<class T> void sort(Array<T>& v);
void f(Array<dcomplex>& cv, Array<int>& ci) {
sort<dcomplex>(cv); // sort(Array<dcomplex>&)
sort<int>(ci); // sort(Array<int>&)
}
template<class U, class V> U convert(V v);
void g(double d) {
int i = convert<int,double>(d); // int convert(double)
char c = convert<char,double>(d); // char convert(double)
}
template<class X, class Y> X f(Y);
template<class X, class Y, class ... Z> X g(Y);
void h() {
int i = f<int>(5.6); // Y is deduced to be double
int j = f(5.6); // ill-formed: X cannot be deduced
f<void>(f<int, bool>); // Y for outer f deduced to be int (*)(bool)
f<void>(f<int>); // ill-formed: f<int> does not denote a single function template specialization
int k = g<int>(5.6); // Y is deduced to be double, Z is deduced to an empty sequence
f<void>(g<int, bool>); // Y for outer f is deduced to be int (*)(bool),
// Z is deduced to an empty sequence
}template <class T> int f(T); // #1 int f(int); // #2 int k = f(1); // uses #2 int l = f<>(1); // uses #1
template<class X, class Y, class Z> X f(Y,Z);
template<class ... Args> void f2();
void g() {
f<int,const char*,double>("aa",3.0);
f<int,const char*>("aa",3.0); // Z is deduced to be double
f<int>("aa",3.0); // Y is deduced to be const char*, and Z is deduced to be double
f("aa",3.0); // error: X cannot be deduced
f2<char, short, int, long>(); // OK
}
namespace A {
struct B { };
template<int X> void f(B);
}
namespace C {
template<class T> void f(T t);
}
void g(A::B b) {
f<3>(b); // ill-formed: not a function call
A::f<3>(b); // well-formed
C::f<3>(b); // ill-formed; argument dependent lookup applies only to unqualified names
using C::f;
f<3>(b); // well-formed because C::f is visible; then A::f is found by argument dependent lookup
}
template<class ... Types> void f(Types ... values);
void g() {
f<int*, float*>(0, 0, 0); // Types is deduced to the sequence int*, float*, int
}
void f(Array<dcomplex>& cv, Array<int>& ci) {
sort(cv); // calls sort(Array<dcomplex>&)
sort(ci); // calls sort(Array<int>&)
}
void g(double d) {
int i = convert<int>(d); // calls convert<int,double>(double)
int c = convert<char>(d); // calls convert<char,double>(double)
}
template <class T> void f(T t);
template <class X> void g(const X x);
template <class Z> void h(Z, Z*);
int main() {
// #1: function type is f(int), t is non const
f<int>(1);
// #2: function type is f(int), t is const
f<const int>(1);
// #3: function type is g(int), x is const
g<int>(1);
// #4: function type is g(int), x is const
g<const int>(1);
// #5: function type is h(int, const int*)
h<const int>(1,0);
}
template <class T, class U = double>
void f(T t = 0, U u = 0);
void g() {
f(1, 'c'); // f<int,char>(1,'c')
f(1); // f<int,double>(1,0)
f(); // error: T cannot be deduced
f<int>(); // f<int,double>(0,0)
f<int,char>(); // f<int,char>(0,0)
}
template <class T> struct A { using X = typename T::X; };
template <class T> typename T::X f(typename A<T>::X);
template <class T> void f(...) { }
template <class T> auto g(typename A<T>::X) -> typename T::X;
template <class T> void g(...) { }
void h() {
f<int>(0); // OK, substituting return type causes deduction to fail
g<int>(0); // error, substituting parameter type instantiates A<int>
}
struct X { };
struct Y {
Y(X){}
};
template <class T> auto f(T t1, T t2) -> decltype(t1 + t2); // #1
X f(Y, Y); // #2
X x1, x2;
X x3 = f(x1, x2); // deduction fails on #1 (cannot add X+X), calls #2
template <class T> int f(T[5]);
int I = f<int>(0);
int j = f<void>(0); // invalid array
template <int I> struct X { };
template <template <class T> class> struct Z { };
template <class T> void f(typename T::Y*){}
template <class T> void g(X<T::N>*){}
template <class T> void h(Z<T::template TT>*){}
struct A {};
struct B { int Y; };
struct C {
typedef int N;
};
struct D {
typedef int TT;
};
int main() {
// Deduction fails in each of these cases:
f<A>(0); // A does not contain a member Y
f<B>(0); // The Y member of B is not a type
g<C>(0); // The N member of C is not a non-type
h<D>(0); // The TT member of D is not a template
}
template <class T, T> struct S {};
template <class T> int f(S<T, T()>*);
struct X {};
int i0 = f<X>(0);
template <class T, T*> int f(int);
int i2 = f<int,1>(0); // can't conv 1 to int*
template <int> int f(int); template <signed char> int f(int); int i1 = f<1000>(0); // OK int i2 = f<1>(0); // ambiguous; not narrowing
template<class T> void f(std::initializer_list<T>);
f({1,2,3}); // T deduced to int
f({1,"asdf"}); // error: T deduced to both int and const char*
template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T
template<class T, int N> void h(T const(&)[N]);
h({1,2,3}); // T deduced to int, N deduced to 3
template<class T> void j(T const(&)[3]);
j({42}); // T deduced to int, array bound not considered
struct Aggr { int i; int j; };
template<int N> void k(Aggr const(&)[N]);
k({1,2,3}); // error: deduction fails, no conversion from int to Aggr
k({{1},{2},{3}}); // OK, N deduced to 3
template<int M, int N> void m(int const(&)[M][N]);
m({{1,2},{3,4}}); // M and N both deduced to 2
template<class T, int N> void n(T const(&)[N], T);
n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3
template<class ... Types> void f(Types& ...);
template<class T1, class ... Types> void g(T1, Types ...);
template<class T1, class ... Types> void g1(Types ..., T1);
void h(int x, float& y) {
const int z = x;
f(x, y, z); // Types is deduced to int, float, const int
g(x, y, z); // T1 is deduced to int; Types is deduced to float, int
g1(x, y, z); // error: Types is not deduced
g1<int, int, int>(x, y, z); // OK, no deduction occurs
}template<class T> int f(const T&); int n1 = f(5); // calls f<int>(const int&) const int i = 0; int n2 = f(i); // calls f<int>(const int&) template <class T> int g(volatile T&); int n3 = g(i); // calls g<const int>(const volatile int&)
template <class T> int f(T&& heisenreference); template <class T> int g(const T&&); int i; int n1 = f(i); // calls f<int&>(int&) int n2 = f(0); // calls f<int>(int&&) int n3 = g(i); // error: would call g<int>(const int&&), which // would bind an rvalue reference to an lvalue template <class T> struct A { template <class U> A(T&&, U&&, int*); // #1: T&& is not a forwarding reference. // U&& is a forwarding reference. A(T&&, int*); // #2 }; template <class T> A(T&&, int*) -> A<T>; // #3: T&& is a forwarding reference. int *ip; A a{i, 0, ip}; // error: cannot deduce from #1 A a0{0, 0, ip}; // uses #1 to deduce A<int> and #1 to initialize A a2{i, ip}; // uses #3 to deduce A<int&> and #2 to initialize
// Only one function of an overload set matches the call so the function parameter is a deduced context. template <class T> int f(T (*p)(T)); int g(int); int g(char); int i = f(g); // calls f(int (*)(int))
// Ambiguous deduction causes the second function parameter to be a non-deduced context. template <class T> int f(T, T (*p)(T)); int g(int); char g(char); int i = f(1, g); // calls f(int, int (*)(int))
// The overload set contains a template, causing the second function parameter to be a non-deduced context. template <class T> int f(T, T (*p)(T)); char g(char); template <class T> T g(T); int i = f(1, g); // calls f(int, int (*)(int))
template <class T> struct Z {
typedef typename T::x xx;
};
template <class T> typename Z<T>::xx f(void *, T); // #1
template <class T> void f(int, T); // #2
struct A {} a;
int main() {
f(1, a); // OK, deduction fails for #1 because there is no conversion from int to void*
}
struct A {
template <class T> operator T***();
};
A a;
const int * const * const * p1 = a; // T is deduced as int, not const int
template<class... Args> void f(Args... args); // #1 template<class T1, class... Args> void f(T1 a1, Args... args); // #2 template<class T1, class T2> void f(T1 a1, T2 a2); // #3 f(); // calls #1 f(1, 2, 3); // calls #2 f(1, 2); // calls #3; non-variadic template #3 is more specialized // than the variadic templates #1 and #2
template <class T> T f(int); // #1 template <class T, class U> T f(U); // #2 void g() { f<int>(1); // calls #1 }
template<class ...> struct Tuple { };
template<class ... Types> void g(Tuple<Types ...>); // #1
template<class T1, class ... Types> void g(Tuple<T1, Types ...>); // #2
template<class T1, class ... Types> void g(Tuple<T1, Types& ...>); // #3
g(Tuple<>()); // calls #1
g(Tuple<int, float>()); // calls #2
g(Tuple<int, float&>()); // calls #3
g(Tuple<int>()); // calls #3
template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T
template<class T> void f(T x, T y) { /* ... */ }
struct A { /* ... */ };
struct B : A { /* ... */ };
void g(A a, B b) {
f(a,b); // error: T could be A or B
f(b,a); // error: T could be A or B
f(a,a); // OK: T is A
f(b,b); // OK: T is B
}
template <class T, class U> void f( T (*)( T, U, U ) );
int g1( int, float, float);
char g2( int, float, float);
int g3( int, char, float);
void r() {
f(g1); // OK: T is int and U is float
f(g2); // error: T could be char or int
f(g3); // error: U could be char or float
}Here is an example where a qualification conversion applies between the
argument type on the function call and the deduced template argument type:
template<class T> void f(const T*) { }
int* p;
void s() {
f(p); // f(const int*)
}Here is an example where the template argument is used to instantiate
a derived class type of the corresponding function parameter type:
template <class T> struct B { };
template <class T> struct D : public B<T> {};
struct D2 : public B<int> {};
template <class T> void f(B<T>&){}
void t() {
D<int> d;
D2 d2;
f(d); // calls f(B<int>&)
f(d2); // calls f(B<int>&)
}T cv-list T T* T& T&& T[integer-constant] template-name<T> (where template-name refers to a class template) type(T) T() T(T) T type::* type T::* T T::* T (type::*)() type (T::*)() type (type::*)(T) type (T::*)(T) T (type::*)(T) T (T::*)() T (T::*)(T) type[i] template-name<i> (where template-name refers to a class template) TT<T> TT<i> TT<>
template<class T1, class... Z> class S; // #1 template<class T1, class... Z> class S<T1, const Z&...> { }; // #2 template<class T1, class T2> class S<T1, const T2&> { }; // #3 S<int, const int&> s; // both #2 and #3 match; #3 is more specialized template<class T, class... U> struct A { }; // #1 template<class T1, class T2, class... U> struct A<T1, T2*, U...> { }; // #2 template<class T1, class T2> struct A<T1, T2> { }; // #3 template struct A<int, int*>; // selects #2
template <class T> void f(T&&);
template <> void f(int&) { } // #1
template <> void f(int&&) { } // #2
void g(int i) {
f(i); // calls f<int&>(int&), i.e., #1
f(0); // calls f<int>(int&&), i.e., #2
}
template<class T, class... U> void f(T*, U...) { } // #1
template<class T> void f(T) { } // #2
template void f(int*); // selects #1
template<long n> struct A { };
template<typename T> struct C;
template<typename T, T n> struct C<A<n>> {
using Q = T;
};
using R = long;
using R = C<A<2>>::Q; // OK; T was deduced to long from the
// template argument value in the type A<2>
template<typename T> struct S;
template<typename T, T n> struct S<int[n]> {
using Q = T;
};
using V = decltype(sizeof 0);
using V = S<int[42]>::Q; // OK; T was deduced to std::size_t from the type int[42]
template<class T, T i> void f(int (&a)[i]);
int v[10];
void g() {
f(v); // OK: T is std::size_t
}
template<int i> void f1(int a[10][i]);
template<int i> void f2(int a[i][20]);
template<int i> void f3(int (&a)[i][20]);
void g() {
int v[10][20];
f1(v); // OK: i deduced to be 20
f1<20>(v); // OK
f2(v); // error: cannot deduce template-argument i
f2<10>(v); // OK
f3(v); // OK: i deduced to be 10
}
template <int i> class A { /* ... */ };
template <int i> void g(A<i+1>);
template <int i> void f(A<i>, A<i+1>);
void k() {
A<1> a1;
A<2> a2;
g(a1); // error: deduction fails for expression i+1
g<0>(a1); // OK
f(a1, a2); // OK
}template<int i, typename T> T deduce(typename A<T>::X x, // T is not deduced here T t, // but T is deduced here typename B<i>::Y y); // i is not deduced here A<int> a; B<77> b; int x = deduce<77>(a.xm, 62, b.ym); // T is deduced to be int, a.xm must be convertible to A<int>::X // i is explicitly specified to be 77, b.ym must be convertible to B<77>::Y
template<int i> class A { /* ... */ };
template<short s> void f(A<s>);
void k1() {
A<1> a;
f(a); // error: deduction fails for conversion from int to short
f<1>(a); // OK
}
template<const short cs> class B { };
template<short s> void g(B<s>);
void k2() {
B<1> b;
g(b); // OK: cv-qualifiers are ignored on template parameter types
}
template<class T> void f(void(*)(T,int));
template<class T> void foo(T,int);
void g(int,int);
void g(char,int);
void h(int,int,int);
void h(char,int);
int m() {
f(&g); // error: ambiguous
f(&h); // OK: void h(char,int) is a unique match
f(&foo); // error: type deduction fails because foo is a template
}
template <class T> void f(T = 5, T = 7);
void g() {
f(1); // OK: call f<int>(1,7)
f(); // error: cannot deduce T
f<int>(); // OK: call f<int>(5,7)
}
template <template <class T> class X> struct A { };
template <template <class T> class X> void f(A<X>) { }
template<class T> struct B { };
A<B> ab;
f(ab); // calls f(A<B>)
template<class> struct X { };
template<class R, class ... ArgTypes> struct X<R(int, ArgTypes ...)> { };
template<class ... Types> struct Y { };
template<class T, class ... Types> struct Y<T, Types& ...> { };
template<class ... Types> int f(void (*)(Types ...));
void g(int, float);
X<int> x1; // uses primary template
X<int(int, float, double)> x2; // uses partial specialization; ArgTypes contains float, double
X<int(float, int)> x3; // uses primary template
Y<> y1; // use primary template; Types is empty
Y<int&, float&, double&> y2; // uses partial specialization; T is int&, Types contains float, double
Y<int, float, double> y3; // uses primary template; Types contains int, float, double
int fv = f(g); // OK; Types contains int, float
template<class T> T max(T a, T b) { return a>b?a:b; }
void f(int a, int b, char c, char d) {
int m1 = max(a,b); // max(int a, int b)
char m2 = max(c,d); // max(char a, char b)
int m3 = max(a,c); // error: cannot generate max(int,char)
}int max(int,int);to the example above would resolve the third call, by providing a function that could be called for max(a,c) after using the standard conversion of char to int for c.
template<class T> struct B { /* ... */ };
template<class T> struct D : public B<T> { /* ... */ };
template<class T> void f(B<T>&);
void g(B<int>& bi, D<int>& di) {
f(bi); // f(bi)
f(di); // f((B<int>&)di)
}template<class T> void f(T*,int); // #1 template<class T> void f(T,char); // #2 void h(int* pi, int i, char c) { f(pi,i); // #1: f<int>(pi,i) f(pi,c); // #2: f<int*>(pi,c) f(i,c); // #2: f<int>(i,c); f(i,i); // #2: f<int>(i,char(i)) }
template<class T> void f(T); // declaration void g() { f("Annemarie"); // call of f<const char*> }
deduction-guide: explicit template-name ( parameter-declaration-clause ) -> simple-template-id ;
template<class T, class D = int>
struct S {
T data;
};
template<class U>
S(U) -> S<typename U::type>;
struct A {
using type = short;
operator type();
};
S x{A()}; // x is of type S<short, int>
try-block: try compound-statement handler-seq
function-try-block: try ctor-initializer compound-statement handler-seq
handler-seq: handler handler-seq
handler: catch ( exception-declaration ) compound-statement
exception-declaration: attribute-specifier-seq type-specifier-seq declarator attribute-specifier-seq type-specifier-seq abstract-declarator ...The optional attribute-specifier-seq in an exception-declaration appertains to the parameter of the catch clause ([except.handle]).
void f() {
goto l1; // ill-formed
goto l2; // ill-formed
try {
goto l1; // OK
goto l2; // ill-formed
l1: ;
} catch (...) {
l2: ;
goto l1; // ill-formed
goto l2; // OK
}
}
lab: try {
T1 t1;
try {
T2 t2;
if (condition)
goto lab;
} catch(...) { /* handler 2 */ }
} catch(...) { /* handler 1 */ }
int f(int);
class C {
int i;
double d;
public:
C(int, double);
};
C::C(int ii, double id)
try : i(f(ii)), d(id) {
// constructor statements
} catch (...) {
// handles exceptions thrown from the ctor-initializer and from the constructor statements
}throw "Help!";
try {
// ...
} catch(const char* p) {
// handle character string exceptions here
}
and
class Overflow {
public:
Overflow(char,double,double);
};
void f(double x) {
throw Overflow('+',x,3.45e107);
}
can be caught by a handler for exceptions of type
Overflow:
try {
f(1.2);
} catch(Overflow& oo) {
// handle exceptions of type Overflow here
}
struct C {
C() { }
C(const C&) {
if (std::uncaught_exceptions()) {
throw 0; // throw during copy to handler's exception-declaration object ([except.handle])
}
}
};
int main() {
try {
throw C(); // calls std::terminate() if construction of the handler's
// exception-declaration object is not elided ([class.copy])
} catch(C) { }
}
struct A { };
struct Y { ~Y() noexcept(false) { throw 0; } };
A f() {
try {
A a;
Y y;
A b;
return {}; // #1
} catch (...) {
}
return {}; // #2
}
class Matherr { /* ... */ virtual void vf(); };
class Overflow: public Matherr { /* ... */ };
class Underflow: public Matherr { /* ... */ };
class Zerodivide: public Matherr { /* ... */ };
void f() {
try {
g();
} catch (Overflow oo) {
// ...
} catch (Matherr mm) {
// ...
}
}noexcept-specifier: noexcept ( constant-expression ) noexcept throw ( )
struct B {
virtual void f() noexcept;
virtual void g();
virtual void h() noexcept = delete;
};
struct D: B {
void f(); // ill-formed
void g() noexcept; // OK
void h() = delete; // OK
};
struct A {
A(int = (A(5), 0)) noexcept;
A(const A&) noexcept;
A(A&&) noexcept;
~A();
};
struct B {
B() throw();
B(const B&) = default; // implicit exception specification is noexcept(true)
B(B&&, int = (throw Y(), 0)) noexcept;
~B() noexcept(false);
};
int n = 7;
struct D : public A, public B {
int * p = new int[n];
// D::D() potentially-throwing, as the new operator may throw bad_alloc or bad_array_new_length
// D::D(const D&) non-throwing
// D::D(D&&) potentially-throwing, as the default argument for B's constructor may throw
// D:: D() potentially-throwing
};preprocessing-file: group
group: group-part group group-part
group-part: control-line if-section text-line # conditionally-supported-directive
control-line: # include pp-tokens new-line # define identifier replacement-list new-line # define identifier lparen identifier-list ) replacement-list new-line # define identifier lparen ... ) replacement-list new-line # define identifier lparen identifier-list , ... ) replacement-list new-line # undef identifier new-line # line pp-tokens new-line # error pp-tokens new-line # pragma pp-tokens new-line # new-line
if-section: if-group elif-groups else-group endif-line
if-group: # if constant-expression new-line group # ifdef identifier new-line group # ifndef identifier new-line group
elif-groups: elif-group elif-groups elif-group
elif-group: # elif constant-expression new-line group
else-group: # else new-line group
endif-line: # endif new-line
text-line: pp-tokens new-line
conditionally-supported-directive: pp-tokens new-line
lparen: a ( character not immediately preceded by white-space
identifier-list: identifier identifier-list , identifier
replacement-list: pp-tokens
pp-tokens: preprocessing-token pp-tokens preprocessing-token
new-line: the new-line character
defined-macro-expression: defined identifier defined ( identifier )
h-preprocessing-token: any preprocessing-token other than >
h-pp-tokens: h-preprocessing-token h-pp-tokens h-preprocessing-token
has-include-expression: __has_include ( < h-char-sequence > ) __has_include ( " q-char-sequence " ) __has_include ( string-literal ) __has_include ( < h-pp-tokens > )
# if constant-expression new-line group # elif constant-expression new-line groupcheck whether the controlling constant expression evaluates to nonzero.
#if 'z' - 'a' == 25
if ('z' - 'a' == 25)# ifdef identifier new-line group # ifndef identifier new-line groupcheck whether the identifier is or is not currently defined as a macro name.
#if __has_include(<optional>) # include <optional> # define have_optional 1 #elif __has_include(<experimental/optional>) # include <experimental/optional> # define have_optional 1 # define experimental_optional 1 #else # define have_optional 0 #endif
# include < h-char-sequence > new-linesearches a sequence of implementation-defined places for a header identified uniquely by the specified sequence between the < and > delimiters, and causes the replacement of that directive by the entire contents of the header.
# include " q-char-sequence " new-linecauses the replacement of that directive by the entire contents of the source file identified by the specified sequence between the " delimiters.
# include < h-char-sequence > new-linewith the identical contained sequence (including > characters, if any) from the original directive.
#include <stdio.h> #include <unistd.h> #include "usefullib.h" #include "myprog.h"
#if VERSION == 1
#define INCFILE "vers1.h"
#elif VERSION == 2
#define INCFILE "vers2.h" // and so on
#else
#define INCFILE "versN.h"
#endif
#include INCFILE# define identifier replacement-list new-linedefines an object-like macro that causes each subsequent instance of the macro name148 to be replaced by the replacement list of preprocessing tokens that constitute the remainder of the directive.149
# define identifier lparen identifier-list ) replacement-list new-line # define identifier lparen ... ) replacement-list new-line # define identifier lparen identifier-list , ... ) replacement-list new-linedefines a function-like macro with parameters, whose use is similar syntactically to a function call.
#define hash_hash # ## #
#define mkstr(a) # a
#define in_between(a) mkstr(a)
#define join(c, d) in_between(c hash_hash d)
char p[] = join(x, y); // equivalent to char p[] = "x ## y";
join(x, y) in_between(x hash_hash y) in_between(x ## y) mkstr(x ## y) "x ## y"In other words, expanding hash_hash produces a new token, consisting of two adjacent sharp signs, but this new token is not the ## operator.
# undef identifier new-linecauses the specified identifier no longer to be defined as a macro name.
#define TABSIZE 100 int table[TABSIZE];
#define max(a, b) ((a) > (b) ? (a) : (b))
#define x 3
#define f(a) f(x * (a))
#undef x
#define x 2
#define g f
#define z z[0]
#define h g(~
#define m(a) a(w)
#define w 0,1
#define t(a) a
#define p() int
#define q(x) x
#define r(x,y) x ## y
#define str(x) # x
f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
g(x+(3,4)-w) | h 5) & m
(f)^m(m);
p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) };
char c[2][6] = { str(hello), str() };
f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);
int i[] = { 1, 23, 4, 5, };
char c[2][6] = { "hello", "" };
#define str(s) # s
#define xstr(s) str(s)
#define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \
x ## s, x ## t)
#define INCFILE(n) vers ## n
#define glue(a, b) a ## b
#define xglue(a, b) glue(a, b)
#define HIGHLOW "hello"
#define LOW LOW ", world"
debug(1, 2);
fputs(str(strncmp("abc\0d", "abc", '\4') // this goes away
== 0) str(: @\n), s);
#include xstr(INCFILE(2).h)
glue(HIGH, LOW);
xglue(HIGH, LOW)
printf("x" "1" "= %d, x" "2" "= %s", x1, x2);
fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s);
#include "vers2.h" (after macro replacement, before file access)
"hello";
"hello" ", world"or, after concatenation of the character string literals,
printf("x1= %d, x2= %s", x1, x2);
fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0: @\n", s);
#include "vers2.h" (after macro replacement, before file access)
"hello";
"hello, world"Space around the
#
and
##
tokens in the macro definition is optional.
#define t(x,y,z) x ## y ## z
int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,),
t(10,,), t(,11,), t(,,12), t(,,) };
int j[] = { 123, 45, 67, 89,
10, 11, 12, };#define OBJ_LIKE (1-1) #define OBJ_LIKE /* white space */ (1-1) /* other */ #define FUNC_LIKE(a) ( a ) #define FUNC_LIKE( a )( /* note the white space */ \ a /* other stuff on this line */ )
#define OBJ_LIKE (0) // different token sequence #define OBJ_LIKE (1 - 1) // different white space #define FUNC_LIKE(b) ( a ) // different parameter usage #define FUNC_LIKE(b) ( b ) // different parameter spelling
#define debug(...) fprintf(stderr, __VA_ARGS__) #define showlist(...) puts(#__VA_ARGS__) #define report(test, ...) ((test) ? puts(#test) : printf(__VA_ARGS__)) debug("Flag"); debug("X = %d\n", x); showlist(The first, second, and third items.); report(x>y, "x is %d but y is %d", x, y);
fprintf(stderr, "Flag");
fprintf(stderr, "X = %d\n", x);
puts("The first, second, and third items.");
((x>y) ? puts("x>y") : printf("x is %d but y is %d", x, y));# line digit-sequence new-linecauses the implementation to behave as if the following sequence of source lines begins with a source line that has a line number as specified by the digit sequence (interpreted as a decimal integer).
# line digit-sequence " s-char-sequence " new-linesets the presumed line number similarly and changes the presumed name of the source file to be the contents of the character string literal.
# pragma pp-tokens new-linecauses the implementation to behave in an implementation-defined manner.
_Pragma ( string-literal )is processed as follows: The string literal is destringized by deleting the L prefix, if present, deleting the leading and trailing double-quotes, replacing each escape sequence \" by a double-quote, and replacing each escape sequence \\ by a single backslash.
#pragma listing on "..\listing.dir"
_Pragma ( "listing on \"..\\listing.dir\"" )The latter form is processed in the same way whether it appears literally as shown, or results from macro replacement, as in:
#define LISTING(x) PRAGMA(listing on #x) #define PRAGMA(x) _Pragma(#x) LISTING( ..\listing.dir )
Clause | Category | |
Language support library | ||
Diagnostics library | ||
General utilities library | ||
Strings library | ||
Localization library | ||
Containers library | ||
Iterators library | ||
Algorithms library | ||
Numerics library | ||
Input/output library | ||
Regular expressions library | ||
Atomic operations library | ||
Thread support library | ||
enum enumerated { , , , , ..... };
inline const ();
inline const ();
inline const ();
inline const ();
.....// For exposition only. // int_type is an integral type capable of representing all values of the bitmask type. enum bitmask : int_type { = 1 << 0, = 1 << 1, = 1 << 2, = 1 << 3, ..... }; inline constexpr (); inline constexpr (); inline constexpr (); inline constexpr (); ..... constexpr bitmask operator&(bitmask X, bitmask Y) { return static_cast<bitmask>( static_cast<int_type>(X) & static_cast<int_type>(Y)); } constexpr bitmask operator|(bitmask X, bitmask Y) { return static_cast<bitmask>( static_cast<int_type>(X) | static_cast<int_type>(Y)); } constexpr bitmask operator^(bitmask X, bitmask Y){ return static_cast<bitmask>( static_cast<int_type>(X) ^ static_cast<int_type>(Y)); } constexpr bitmask operator~(bitmask X){ return static_cast<bitmask>(~static_cast<int_type>(X)); } bitmask& operator&=(bitmask& X, bitmask Y){ X = X & Y; return X; } bitmask& operator|=(bitmask& X, bitmask Y) { X = X | Y; return X; } bitmask& operator^=(bitmask& X, bitmask Y) { X = X ^ Y; return X; }
streambuf* sb; // exposition only
<algorithm> | <future> | <numeric> | <strstream> |
<any> | <initializer_list> | <optional> | <system_error> |
<array> | <iomanip> | <ostream> | <thread> |
<atomic> | <ios> | <queue> | <tuple> |
<bitset> | <iosfwd> | <random> | <type_traits> |
<chrono> | <iostream> | <ratio> | <typeindex> |
<codecvt> | <istream> | <regex> | <typeinfo> |
<complex> | <iterator> | <scoped_allocator> | <unordered_map> |
<condition_variable> | <limits> | <set> | <unordered_set> |
<deque> | <list> | <shared_mutex> | <utility> |
<exception> | <locale> | <sstream> | <valarray> |
<execution> | <map> | <stack> | <variant> |
<filesystem> | <memory> | <stdexcept> | <vector> |
<forward_list> | <memory_resource> | <streambuf> | |
<fstream> | <mutex> | <string> | |
<functional> | <new> | <string_view> |
<cassert> | <cinttypes> | <csignal> | <cstdio> | <cwchar> |
<ccomplex> | <ciso646> | <cstdalign> | <cstdlib> | <cwctype> |
<cctype> | <climits> | <cstdarg> | <cstring> | |
<cerrno> | <clocale> | <cstdbool> | <ctgmath> | |
<cfenv> | <cmath> | <cstddef> | <ctime> | |
<cfloat> | <csetjmp> | <cstdint> | <cuchar> |
abort_handler_s | mbstowcs_s | strncat_s | vswscanf_s |
asctime_s | memcpy_s | strncpy_s | vwprintf_s |
bsearch_s | memmove_s | strtok_s | vwscanf_s |
constraint_handler_t | memset_s | swprintf_s | wcrtomb_s |
ctime_s | printf_s | swscanf_s | wcscat_s |
errno_t | qsort_s | tmpfile_s | wcscpy_s |
fopen_s | RSIZE_MAX | TMP_MAX_S | wcsncat_s |
fprintf_s | rsize_t | tmpnam_s | wcsncpy_s |
freopen_s | scanf_s | vfprintf_s | wcsnlen_s |
fscanf_s | set_constraint_handler_s | vfscanf_s | wcsrtombs_s |
fwprintf_s | snprintf_s | vfwprintf_s | wcstok_s |
fwscanf_s | snwprintf_s | vfwscanf_s | wcstombs_s |
getenv_s | sprintf_s | vprintf_s | wctomb_s |
gets_s | sscanf_s | vscanf_s | wmemcpy_s |
gmtime_s | strcat_s | vsnprintf_s | wmemmove_s |
ignore_handler_s | strcpy_s | vsnwprintf_s | wprintf_s |
L_tmpnam_s | strerror_s | vsprintf_s | wscanf_s |
localtime_s | strerrorlen_s | vsscanf_s | |
mbsrtowcs_s | strlen_s | vswprintf_s |
Subclause | Header(s) | |
<ciso646> | ||
Types | <cstddef> | |
Implementation properties | <cfloat> <limits> <climits> | |
Integer types | <cstdint> | |
Start and termination | <cstdlib> | |
Dynamic memory management | <new> | |
Type identification | <typeinfo> | |
Exception handling | <exception> | |
Initializer lists | <initializer_list> | |
Other runtime support | <cstdarg> | |
Type traits | <type_traits> | |
Atomics | <atomic> | |
Deprecated headers | <cstdalign> <cstdbool> | |
Expression | Return type | Requirement |
a == b | convertible to bool |
Expression | Return type | Requirement |
a < b | convertible to bool | < is a strict weak ordering relation ([alg.sorting]) |
Expression | Post-condition |
T t; | object t is default-initialized |
T u{}; | object u is value-initialized or aggregate-initialized |
T() T{} | an object of type T is value-initialized
or aggregate-initialized |
Expression | Post-condition |
T u = rv; | u is equivalent to the value of rv before the construction |
T(rv) | T(rv) is equivalent to the value of rv before the construction |
Expression | Post-condition |
T u = v; | the value of v is unchanged and is equivalent to u |
T(v) | the value of v is unchanged and is equivalent to T(v) |
Expression | Return type | Return value | Post-condition |
t = rv | T& | t | If t and rv do not refer to the same object,
t is equivalent to the value of rv before the assignment |
rv's state is unspecified. | |||
Expression | Return type | Return value | Post-condition |
t = v | T& | t | t is equivalent to v, the value of v is unchanged |
#include <utility> // Requires: std::forward<T>(t) shall be swappable with std::forward<U>(u). template <class T, class U> void value_swap(T&& t, U&& u) { using std::swap; swap(std::forward<T>(t), std::forward<U>(u)); // OK: uses “swappable with” conditions // for rvalues and lvalues } // Requires: lvalues of T shall be swappable. template <class T> void lv_swap(T& t1, T& t2) { using std::swap; swap(t1, t2); // OK: uses swappable conditions for } // lvalues of type T namespace N { struct A { int m; }; struct Proxy { A* a; }; Proxy proxy(A& a) { return Proxy{ &a }; } void swap(A& x, Proxy p) { std::swap(x.m, p.a->m); // OK: uses context equivalent to swappable // conditions for fundamental types } void swap(Proxy p, A& x) { swap(x, p); } // satisfy symmetry constraint } int main() { int i = 1, j = 2; lv_swap(i, j); assert(i == 2 && j == 1); N::A a1 = { 5 }, a2 = { -5 }; value_swap(a1, proxy(a2)); assert(a1.m == -5 && a2.m == 5); }
Expression | Return type | Operational semantics |
P u(np); | Postconditions: u == nullptr | |
P u = np; | ||
P(np) | Postconditions: P(np) == nullptr | |
t = np | P& | Postconditions: t == nullptr |
a != b | contextually convertible to bool | !(a == b) |
a == np | contextually convertible to bool | a == P() |
np == a | ||
a != np | contextually convertible to bool | !(a == np) |
np != a |
Variable | Definition |
T, U, C | any cv-unqualified object type ([basic.types]) |
X | an Allocator class for type T |
Y | the corresponding Allocator class for type U |
XX | the type allocator_traits<X> |
YY | the type allocator_traits<Y> |
a, a1, a2 | lvalues of type X |
u | the name of a variable being declared |
b | a value of type Y |
c | a pointer of type C* through which indirection is valid |
p | a value of type XX::pointer, obtained
by calling a1.allocate, where a1 == a |
q | |
w | a value of type XX::void_pointer obtained by
conversion from a value p |
x | a value of type XX::const_void_pointer obtained by
conversion from a value q or a value w |
y | a value of type XX::const_void_pointer obtained by
conversion from a result value of YY::allocate, or else a value of
type (possibly const) std::nullptr_t. |
n | a value of type XX::size_type. |
Args | a template parameter pack |
args | a function parameter pack with the pattern Args&& |
Expression | Return type | Assertion/note | Default |
pre-/post-condition | |||
X::pointer | T* | ||
X::const_pointer | X::pointer is convertible to X::const_pointer | pointer_traits<X::pointer>::rebind<const T> | |
X::void_pointer Y::void_pointer | pointer_traits<X::pointer>::rebind<void> | ||
X::const_void_pointer Y::const_void_pointer | X::pointer, X::const_pointer, and X::void_pointer are convertible to X::const_void_pointer. | pointer_traits<X::pointer>::rebind<const void> | |
X::value_type | Identical to T | ||
X::size_type | unsigned integer type | a type that can represent the size of the largest object in the allocation model. | make_unsigned_t<X::difference_type> |
X::difference_type | signed integer type | a type that can represent the difference between any two pointers
in the allocation model. | pointer_traits<X::pointer>::difference_type |
typename X::template rebind<U>::other | Y | See Note A, below. | |
*p | T& | ||
*q | const T& | *q refers to the same object as *p | |
p->m | type of T::m | equivalent to (*p).m | |
q->m | type of T::m | equivalent to (*q).m | |
static_cast<X::pointer>(w) | X::pointer | static_cast<X::pointer>(w) == p | |
static_cast<X::const_pointer>(x) | X::const_pointer | static_cast< X::const_pointer>(x) == q | |
pointer_traits<X::pointer>::pointer_to(r) | X::pointer | ||
a.allocate(n) | X::pointer | ||
a.allocate(n, y) | X::pointer | Same as a.allocate(n). The use of y is unspecified, but
it is intended as an aid to locality. | a.allocate(n) |
a.deallocate(p,n) | (not used) | Requires: p shall be a value returned by an earlier call
to allocate that has not been invalidated by
an intervening call to deallocate. | |
a.max_size() | X::size_type | the largest value that can meaningfully be passed to X::allocate() | numeric_limits<size_type>::max() / sizeof(value_type) |
a1 == a2 | bool | returns true only if storage allocated from each can
be deallocated via the other. operator== shall be reflexive, symmetric,
and transitive, and shall not exit via an exception. | |
a1 != a2 | bool | same as !(a1 == a2) | |
a == b | bool | same as a == Y::rebind<T>::other(b) | |
a != b | bool | same as !(a == b) | |
X u(a); X u = a; | Shall not exit via an exception. Postconditions: u == a | ||
X u(b); | Shall not exit via an exception. Postconditions: Y(u) == b, u == X(b) | ||
X u(std::move(a)); X u = std::move(a); | Shall not exit via an exception. | ||
X u(std::move(b)); | Shall not exit via an exception. | ||
a.construct(c, args) | (not used) | Effects: Constructs an object of type C at
c | ::new ((void*)c) C(forward<Args>(args)...) |
a.destroy(c) | (not used) | Effects: Destroys the object at c | c->~C() |
a.select_on_container_copy_construction() | X | Typically returns either a or X() | return a; |
X::propagate_on_container_copy_assignment | Identical to or derived from true_type or false_type | true_type only if an allocator of type X should be copied
when the client container is copy-assigned. See Note B, below. | false_type |
X::propagate_on_container_move_assignment | Identical to or derived from true_type or false_type | true_type only if an allocator of type X should be moved
when the client container is move-assigned. See Note B, below. | false_type |
X::propagate_on_- container_swap | Identical to or derived from true_type or false_type | See Note B, below. | false_type |
X::is_always_equal | Identical to or derived from true_type or false_type | true_type only if the expression a1 == a2 is guaranteed
to be true for any two (possibly const) values
a1, a2 of type X. | is_empty<X>::type |
w1 == w2 w1 != w2either or both objects may be replaced by an equivalently-valued object of type X::const_void_pointer with no change in semantics.
p1 == p2 p1 != p2 p1 < p2 p1 <= p2 p1 >= p2 p1 > p2 p1 - p2either or both objects may be replaced by an equivalently-valued object of type X::const_pointer with no change in semantics.
template <class Tp>
struct SimpleAllocator {
typedef Tp value_type;
SimpleAllocator(ctor args);
template <class T> SimpleAllocator(const SimpleAllocator<T>& other);
Tp* allocate(std::size_t n);
void deallocate(Tp* p, std::size_t n);
};
template <class T, class U>
bool operator==(const SimpleAllocator<T>&, const SimpleAllocator<U>&);
template <class T, class U>
bool operator!=(const SimpleAllocator<T>&, const SimpleAllocator<U>&);operator new(std::size_t) operator new(std::size_t, std::align_val_t) operator new(std::size_t, const std::nothrow_t&) operator new(std::size_t, std::align_val_t, const std::nothrow_t&)
operator delete(void*) operator delete(void*, std::size_t) operator delete(void*, std::align_val_t) operator delete(void*, std::size_t, std::align_val_t) operator delete(void*, const std::nothrow_t&) operator delete(void*, std::align_val_t, const std::nothrow_t&)
operator new[](std::size_t) operator new[](std::size_t, std::align_val_t) operator new[](std::size_t, const std::nothrow_t&) operator new[](std::size_t, std::align_val_t, const std::nothrow_t&)
operator delete[](void*) operator delete[](void*, std::size_t) operator delete[](void*, std::align_val_t) operator delete[](void*, std::size_t, std::align_val_t) operator delete[](void*, const std::nothrow_t&) operator delete[](void*, std::align_val_t, const std::nothrow_t&)
*out_stream << value; if (delim != 0) *out_stream << delim; return *this;
Subclause | Header(s) | |
Common definitions | <cstddef> | |
<cstdlib> | ||
Implementation properties | <limits> | |
<climits> | ||
<cfloat> | ||
Integer types | <cstdint> | |
Start and termination | <cstdlib> | |
Dynamic memory management | <new> | |
Type identification | <typeinfo> | |
Exception handling | <exception> | |
Initializer lists | <initializer_list> | |
Other runtime support | <csignal> | |
<csetjmp> | ||
<cstdarg> | ||
<cstdlib> | ||
namespace std {
using ptrdiff_t = see below;
using size_t = see below;
using max_align_t = see below;
using nullptr_t = decltype(nullptr);
enum class byte : unsigned char {};
// [support.types.byteops], byte type operations
template <class IntType>
constexpr byte& operator<<=(byte& b, IntType shift) noexcept;
template <class IntType>
constexpr byte operator<<(byte b, IntType shift) noexcept;
template <class IntType>
constexpr byte& operator>>=(byte& b, IntType shift) noexcept;
template <class IntType>
constexpr byte operator>>(byte b, IntType shift) noexcept;
constexpr byte& operator|=(byte& l, byte r) noexcept;
constexpr byte operator|(byte l, byte r) noexcept;
constexpr byte& operator&=(byte& l, byte r) noexcept;
constexpr byte operator&(byte l, byte r) noexcept;
constexpr byte& operator^=(byte& l, byte r) noexcept;
constexpr byte operator^(byte l, byte r) noexcept;
constexpr byte operator~(byte b) noexcept;
template <class IntType>
constexpr IntType to_integer(byte b) noexcept;
}
#define NULL see below
#define offsetof(P, D) see below
namespace std {
using size_t = see below;
using div_t = see below;
using ldiv_t = see below;
using lldiv_t = see below;
}
#define NULL see below
#define EXIT_FAILURE see below
#define EXIT_SUCCESS see below
#define RAND_MAX see below
#define MB_CUR_MAX see below
namespace std {
// Exposition-only function type aliases
extern "C" using c-atexit-handler = void(); // exposition only
extern "C++" using atexit-handler = void(); // exposition only
extern "C" using c-compare-pred = int(const void*, const void*); // exposition only
extern "C++" using compare-pred = int(const void*, const void*); // exposition only
// [support.start.term], start and termination
[[noreturn]] void abort() noexcept;
int atexit(c-atexit-handler* func) noexcept;
int atexit(atexit-handler* func) noexcept;
int at_quick_exit(c-atexit-handler* func) noexcept;
int at_quick_exit(atexit-handler* func) noexcept;
[[noreturn]] void exit(int status);
[[noreturn]] void _Exit(int status) noexcept;
[[noreturn]] void quick_exit(int status) noexcept;
char* getenv(const char* name);
int system(const char* string);
// [c.malloc], C library memory allocation
void* aligned_alloc(size_t alignment, size_t size);
void* calloc(size_t nmemb, size_t size);
void free(void* ptr);
void* malloc(size_t size);
void* realloc(void* ptr, size_t size);
double atof(const char* nptr);
int atoi(const char* nptr);
long int atol(const char* nptr);
long long int atoll(const char* nptr);
double strtod(const char* nptr, char** endptr);
float strtof(const char* nptr, char** endptr);
long double strtold(const char* nptr, char** endptr);
long int strtol(const char* nptr, char** endptr, int base);
long long int strtoll(const char* nptr, char** endptr, int base);
unsigned long int strtoul(const char* nptr, char** endptr, int base);
unsigned long long int strtoull(const char* nptr, char** endptr, int base);
// [c.mb.wcs], multibyte / wide string and character conversion functions
int mblen(const char* s, size_t n);
int mbtowc(wchar_t* pwc, const char* s, size_t n);
int wctomb(char* s, wchar_t wchar);
size_t mbstowcs(wchar_t* pwcs, const char* s, size_t n);
size_t wcstombs(char* s, const wchar_t* pwcs, size_t n);
// [alg.c.library], C standard library algorithms
void* bsearch(const void* key, const void* base, size_t nmemb, size_t size,
c-compare-pred* compar);
void* bsearch(const void* key, const void* base, size_t nmemb, size_t size,
compare-pred* compar);
void qsort(void* base, size_t nmemb, size_t size, c-compare-pred* compar);
void qsort(void* base, size_t nmemb, size_t size, compare-pred* compar);
// [c.math.rand], low-quality random number generation
int rand();
void srand(unsigned int seed);
// [c.math.abs], absolute values
int abs(int j);
long int abs(long int j);
long long int abs(long long int j);
float abs(float j);
double abs(double j);
long double abs(long double j);
long int labs(long int j);
long long int llabs(long long int j);
div_t div(int numer, int denom);
ldiv_t div(long int numer, long int denom); // see [library.c]
lldiv_t div(long long int numer, long long int denom); // see [library.c]
ldiv_t ldiv(long int numer, long int denom);
lldiv_t lldiv(long long int numer, long long int denom);
}template <class IntType>
constexpr byte& operator<<=(byte& b, IntType shift) noexcept;
template <class IntType>
constexpr byte operator<<(byte b, IntType shift) noexcept;
template <class IntType>
constexpr byte& operator>>=(byte& b, IntType shift) noexcept;
template <class IntType>
constexpr byte operator>>(byte b, IntType shift) noexcept;
constexpr byte& operator|=(byte& l, byte r) noexcept;
return l = byte(static_cast<unsigned char>(l) | static_cast<unsigned char>(r));
constexpr byte operator|(byte l, byte r) noexcept;
return byte(static_cast<unsigned char>(l) | static_cast<unsigned char>(r));
constexpr byte& operator&=(byte& l, byte r) noexcept;
return l = byte(static_cast<unsigned char>(l) & static_cast<unsigned char>(r));
constexpr byte operator&(byte l, byte r) noexcept;
return byte(static_cast<unsigned char>(l) & static_cast<unsigned char>(r));
constexpr byte& operator^=(byte& l, byte r) noexcept;
return l = byte(static_cast<unsigned char>(l) ^ static_cast<unsigned char>(r));
constexpr byte operator^(byte l, byte r) noexcept;
return byte(static_cast<unsigned char>(l) ^ static_cast<unsigned char>(r));
constexpr byte operator~(byte b) noexcept;
template <class IntType>
constexpr IntType to_integer(byte b) noexcept;
namespace std {
// [fp.style], floating-point type properties
enum float_round_style;
enum float_denorm_style;
// [numeric.limits], class template numeric_limits
template<class T> class numeric_limits;
template<> class numeric_limits<bool>;
template<> class numeric_limits<char>;
template<> class numeric_limits<signed char>;
template<> class numeric_limits<unsigned char>;
template<> class numeric_limits<char16_t>;
template<> class numeric_limits<char32_t>;
template<> class numeric_limits<wchar_t>;
template<> class numeric_limits<short>;
template<> class numeric_limits<int>;
template<> class numeric_limits<long>;
template<> class numeric_limits<long long>;
template<> class numeric_limits<unsigned short>;
template<> class numeric_limits<unsigned int>;
template<> class numeric_limits<unsigned long>;
template<> class numeric_limits<unsigned long long>;
template<> class numeric_limits<float>;
template<> class numeric_limits<double>;
template<> class numeric_limits<long double>;
}
namespace std {
enum float_round_style {
round_indeterminate = -1,
round_toward_zero = 0,
round_to_nearest = 1,
round_toward_infinity = 2,
round_toward_neg_infinity = 3
};
}
namespace std {
enum float_denorm_style {
denorm_indeterminate = -1,
denorm_absent = 0,
denorm_present = 1
};
}
namespace std {
template<class T> class numeric_limits {
public:
static constexpr bool is_specialized = false;
static constexpr T min() noexcept { return T(); }
static constexpr T max() noexcept { return T(); }
static constexpr T lowest() noexcept { return T(); }
static constexpr int digits = 0;
static constexpr int digits10 = 0;
static constexpr int max_digits10 = 0;
static constexpr bool is_signed = false;
static constexpr bool is_integer = false;
static constexpr bool is_exact = false;
static constexpr int radix = 0;
static constexpr T epsilon() noexcept { return T(); }
static constexpr T round_error() noexcept { return T(); }
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_NaN = false;
static constexpr bool has_signaling_NaN = false;
static constexpr float_denorm_style has_denorm = denorm_absent;
static constexpr bool has_denorm_loss = false;
static constexpr T infinity() noexcept { return T(); }
static constexpr T quiet_NaN() noexcept { return T(); }
static constexpr T signaling_NaN() noexcept { return T(); }
static constexpr T denorm_min() noexcept { return T(); }
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = false;
static constexpr bool is_modulo = false;
static constexpr bool traps = false;
static constexpr bool tinyness_before = false;
static constexpr float_round_style round_style = round_toward_zero;
};
template<class T> class numeric_limits<const T>;
template<class T> class numeric_limits<volatile T>;
template<class T> class numeric_limits<const volatile T>;
}static constexpr T min() noexcept;
static constexpr T max() noexcept;
static constexpr T lowest() noexcept;
static constexpr int digits;
static constexpr int digits10;
static constexpr int max_digits10;
static constexpr bool is_signed;
static constexpr bool is_integer;
static constexpr bool is_exact;
static constexpr int radix;
static constexpr T epsilon() noexcept;
static constexpr T round_error() noexcept;
static constexpr int min_exponent;
static constexpr int min_exponent10;
static constexpr int max_exponent;
static constexpr int max_exponent10;
static constexpr bool has_infinity;
static constexpr bool has_quiet_NaN;
static constexpr bool has_signaling_NaN;
static constexpr float_denorm_style has_denorm;
static constexpr bool has_denorm_loss;
static constexpr T infinity() noexcept;
static constexpr T quiet_NaN() noexcept;
static constexpr T signaling_NaN() noexcept;
static constexpr T denorm_min() noexcept;
static constexpr bool is_iec559;
static constexpr bool is_bounded;
static constexpr bool is_modulo;
static constexpr bool traps;
static constexpr bool tinyness_before;
static constexpr float_round_style round_style;
namespace std {
template<> class numeric_limits<float> {
public:
static constexpr bool is_specialized = true;
static constexpr float min() noexcept { return 1.17549435E-38F; }
static constexpr float max() noexcept { return 3.40282347E+38F; }
static constexpr float lowest() noexcept { return -3.40282347E+38F; }
static constexpr int digits = 24;
static constexpr int digits10 = 6;
static constexpr int max_digits10 = 9;
static constexpr bool is_signed = true;
static constexpr bool is_integer = false;
static constexpr bool is_exact = false;
static constexpr int radix = 2;
static constexpr float epsilon() noexcept { return 1.19209290E-07F; }
static constexpr float round_error() noexcept { return 0.5F; }
static constexpr int min_exponent = -125;
static constexpr int min_exponent10 = - 37;
static constexpr int max_exponent = +128;
static constexpr int max_exponent10 = + 38;
static constexpr bool has_infinity = true;
static constexpr bool has_quiet_NaN = true;
static constexpr bool has_signaling_NaN = true;
static constexpr float_denorm_style has_denorm = denorm_absent;
static constexpr bool has_denorm_loss = false;
static constexpr float infinity() noexcept { return value; }
static constexpr float quiet_NaN() noexcept { return value; }
static constexpr float signaling_NaN() noexcept { return value; }
static constexpr float denorm_min() noexcept { return min(); }
static constexpr bool is_iec559 = true;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = false;
static constexpr bool traps = true;
static constexpr bool tinyness_before = true;
static constexpr float_round_style round_style = round_to_nearest;
};
}
namespace std {
template<> class numeric_limits<bool> {
public:
static constexpr bool is_specialized = true;
static constexpr bool min() noexcept { return false; }
static constexpr bool max() noexcept { return true; }
static constexpr bool lowest() noexcept { return false; }
static constexpr int digits = 1;
static constexpr int digits10 = 0;
static constexpr int max_digits10 = 0;
static constexpr bool is_signed = false;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr int radix = 2;
static constexpr bool epsilon() noexcept { return 0; }
static constexpr bool round_error() noexcept { return 0; }
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_NaN = false;
static constexpr bool has_signaling_NaN = false;
static constexpr float_denorm_style has_denorm = denorm_absent;
static constexpr bool has_denorm_loss = false;
static constexpr bool infinity() noexcept { return 0; }
static constexpr bool quiet_NaN() noexcept { return 0; }
static constexpr bool signaling_NaN() noexcept { return 0; }
static constexpr bool denorm_min() noexcept { return 0; }
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = false;
static constexpr bool traps = false;
static constexpr bool tinyness_before = false;
static constexpr float_round_style round_style = round_toward_zero;
};
}#define CHAR_BIT see below #define SCHAR_MIN see below #define SCHAR_MAX see below #define UCHAR_MAX see below #define CHAR_MIN see below #define CHAR_MAX see below #define MB_LEN_MAX see below #define SHRT_MIN see below #define SHRT_MAX see below #define USHRT_MAX see below #define INT_MIN see below #define INT_MAX see below #define UINT_MAX see below #define LONG_MIN see below #define LONG_MAX see below #define ULONG_MAX see below #define LLONG_MIN see below #define LLONG_MAX see below #define ULLONG_MAX see below
#define FLT_ROUNDS see below #define FLT_EVAL_METHOD see below #define FLT_HAS_SUBNORM see below #define DBL_HAS_SUBNORM see below #define LDBL_HAS_SUBNORM see below #define FLT_RADIX see below #define FLT_MANT_DIG see below #define DBL_MANT_DIG see below #define LDBL_MANT_DIG see below #define FLT_DECIMAL_DIG see below #define DBL_DECIMAL_DIG see below #define LDBL_DECIMAL_DIG see below #define DECIMAL_DIG see below #define FLT_DIG see below #define DBL_DIG see below #define LDBL_DIG see below #define FLT_MIN_EXP see below #define DBL_MIN_EXP see below #define LDBL_MIN_EXP see below #define FLT_MIN_10_EXP see below #define DBL_MIN_10_EXP see below #define LDBL_MIN_10_EXP see below #define FLT_MAX_EXP see below #define DBL_MAX_EXP see below #define LDBL_MAX_EXP see below #define FLT_MAX_10_EXP see below #define DBL_MAX_10_EXP see below #define LDBL_MAX_10_EXP see below #define FLT_MAX see below #define DBL_MAX see below #define LDBL_MAX see below #define FLT_EPSILON see below #define DBL_EPSILON see below #define LDBL_EPSILON see below #define FLT_MIN see below #define DBL_MIN see below #define LDBL_MIN see below #define FLT_TRUE_MIN see below #define DBL_TRUE_MIN see below #define LDBL_TRUE_MIN see below
namespace std {
using int8_t = signed integer type; // optional
using int16_t = signed integer type; // optional
using int32_t = signed integer type; // optional
using int64_t = signed integer type; // optional
using int_fast8_t = signed integer type;
using int_fast16_t = signed integer type;
using int_fast32_t = signed integer type;
using int_fast64_t = signed integer type;
using int_least8_t = signed integer type;
using int_least16_t = signed integer type;
using int_least32_t = signed integer type;
using int_least64_t = signed integer type;
using intmax_t = signed integer type;
using intptr_t = signed integer type; // optional
using uint8_t = unsigned integer type; // optional
using uint16_t = unsigned integer type; // optional
using uint32_t = unsigned integer type; // optional
using uint64_t = unsigned integer type; // optional
using uint_fast8_t = unsigned integer type;
using uint_fast16_t = unsigned integer type;
using uint_fast32_t = unsigned integer type;
using uint_fast64_t = unsigned integer type;
using uint_least8_t = unsigned integer type;
using uint_least16_t = unsigned integer type;
using uint_least32_t = unsigned integer type;
using uint_least64_t = unsigned integer type;
using uintmax_t = unsigned integer type;
using uintptr_t = unsigned integer type; // optional
}
INT_[FAST LEAST]{8 16 32 64}_MIN
[U]INT_[FAST LEAST]{8 16 32 64}_MAX
INT{MAX PTR}_MIN
[U]INT{MAX PTR}_MAX
{PTRDIFF SIG_ATOMIC WCHAR WINT}{_MAX _MIN}
SIZE_MAX
[U]INT{8 16 32 64 MAX}_C[[noreturn]] void _Exit(int status) noexcept;
[[noreturn]] void abort() noexcept;
int atexit(c-atexit-handler* f) noexcept;
int atexit(atexit-handler* f) noexcept;
[[noreturn]] void exit(int status);
int at_quick_exit(c-atexit-handler* f) noexcept;
int at_quick_exit(atexit-handler* f) noexcept;
[[noreturn]] void quick_exit(int status) noexcept;
namespace std {
class bad_alloc;
class bad_array_new_length;
enum class align_val_t : size_t {};
struct nothrow_t { explicit nothrow_t() = default; };
extern const nothrow_t nothrow;
using new_handler = void (*)();
new_handler get_new_handler() noexcept;
new_handler set_new_handler(new_handler new_p) noexcept;
// [ptr.launder], pointer optimization barrier
template <class T> constexpr T* launder(T* p) noexcept;
// [hardware.interference], hardware interference size
inline constexpr size_t hardware_destructive_interference_size = implementation-defined;
inline constexpr size_t hardware_constructive_interference_size = implementation-defined;
}
void* operator new(std::size_t size);
void* operator new(std::size_t size, std::align_val_t alignment);
void* operator new(std::size_t size, const std::nothrow_t&) noexcept;
void* operator new(std::size_t size, std::align_val_t alignment,
const std::nothrow_t&) noexcept;
void operator delete(void* ptr) noexcept;
void operator delete(void* ptr, std::size_t size) noexcept;
void operator delete(void* ptr, std::align_val_t alignment) noexcept;
void operator delete(void* ptr, std::size_t size, std::align_val_t alignment) noexcept;
void operator delete(void* ptr, const std::nothrow_t&) noexcept;
void operator delete(void* ptr, std::align_val_t alignment,
const std::nothrow_t&) noexcept;
void* operator new[](std::size_t size);
void* operator new[](std::size_t size, std::align_val_t alignment);
void* operator new[](std::size_t size, const std::nothrow_t&) noexcept;
void* operator new[](std::size_t size, std::align_val_t alignment,
const std::nothrow_t&) noexcept;
void operator delete[](void* ptr) noexcept;
void operator delete[](void* ptr, std::size_t size) noexcept;
void operator delete[](void* ptr, std::align_val_t alignment) noexcept;
void operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexcept;
void operator delete[](void* ptr, const std::nothrow_t&) noexcept;
void operator delete[](void* ptr, std::align_val_t alignment,
const std::nothrow_t&) noexcept;
void* operator new (std::size_t size, void* ptr) noexcept;
void* operator new[](std::size_t size, void* ptr) noexcept;
void operator delete (void* ptr, void*) noexcept;
void operator delete[](void* ptr, void*) noexcept;See also: [intro.memory], [basic.stc.dynamic],
[expr.new], [expr.delete], [class.free],
[memory].void* operator new(std::size_t size);
void* operator new(std::size_t size, std::align_val_t alignment);
void* operator new(std::size_t size, const std::nothrow_t&) noexcept;
void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept;
void operator delete(void* ptr) noexcept;
void operator delete(void* ptr, std::size_t size) noexcept;
void operator delete(void* ptr, std::align_val_t alignment) noexcept;
void operator delete(void* ptr, std::size_t size, std::align_val_t alignment) noexcept;
void operator delete(void* ptr, const std::nothrow_t&) noexcept;
void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept;
void* operator new[](std::size_t size);
void* operator new[](std::size_t size, std::align_val_t alignment);
void* operator new[](std::size_t size, const std::nothrow_t&) noexcept;
void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept;
void operator delete[](void* ptr) noexcept;
void operator delete[](void* ptr, std::size_t size) noexcept;
void operator delete[](void* ptr, std::align_val_t alignment) noexcept;
void operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexcept;
void operator delete[](void* ptr, const std::nothrow_t&) noexcept;
void operator delete[](void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept;
void* operator new(std::size_t size, void* ptr) noexcept;
void* operator new[](std::size_t size, void* ptr) noexcept;
void operator delete(void* ptr, void*) noexcept;
void operator delete[](void* ptr, void*) noexcept;
namespace std {
class bad_alloc : public exception {
public:
bad_alloc() noexcept;
bad_alloc(const bad_alloc&) noexcept;
bad_alloc& operator=(const bad_alloc&) noexcept;
const char* what() const noexcept override;
};
}bad_alloc() noexcept;
bad_alloc(const bad_alloc&) noexcept;
bad_alloc& operator=(const bad_alloc&) noexcept;
const char* what() const noexcept override;
namespace std {
class bad_array_new_length : public bad_alloc {
public:
bad_array_new_length() noexcept;
const char* what() const noexcept override;
};
}bad_array_new_length() noexcept;
const char* what() const noexcept override;
using new_handler = void (*)();
new_handler set_new_handler(new_handler new_p) noexcept;
template <class T> constexpr T* launder(T* p) noexcept;
struct X { const int n; };
X *p = new X{3};
const int a = p->n;
new (p) X{5}; // p does not point to new object ([basic.life]) because X::n is const
const int b = p->n; // undefined behavior
const int c = std::launder(p)->n; // OK
inline constexpr size_t hardware_destructive_interference_size = implementation-defined;
struct keep_apart {
alignas(hardware_destructive_interference_size) atomic<int> cat;
alignas(hardware_destructive_interference_size) atomic<int> dog;
};inline constexpr size_t hardware_constructive_interference_size = implementation-defined;
struct together {
atomic<int> dog;
int puppy;
};
struct kennel {
// Other data members...
alignas(sizeof(together)) together pack;
// Other data members...
};
static_assert(sizeof(together) <= hardware_constructive_interference_size);
namespace std {
class type_info;
class bad_cast;
class bad_typeid;
}See also: [expr.dynamic.cast], [expr.typeid].
namespace std {
class type_info {
public:
virtual ~type_info();
bool operator==(const type_info& rhs) const noexcept;
bool operator!=(const type_info& rhs) const noexcept;
bool before(const type_info& rhs) const noexcept;
size_t hash_code() const noexcept;
const char* name() const noexcept;
type_info(const type_info& rhs) = delete; // cannot be copied
type_info& operator=(const type_info& rhs) = delete; // cannot be copied
};
}bool operator==(const type_info& rhs) const noexcept;
bool operator!=(const type_info& rhs) const noexcept;
bool before(const type_info& rhs) const noexcept;
size_t hash_code() const noexcept;
const char* name() const noexcept;
namespace std {
class bad_cast : public exception {
public:
bad_cast() noexcept;
bad_cast(const bad_cast&) noexcept;
bad_cast& operator=(const bad_cast&) noexcept;
const char* what() const noexcept override;
};
}bad_cast() noexcept;
bad_cast(const bad_cast&) noexcept;
bad_cast& operator=(const bad_cast&) noexcept;
const char* what() const noexcept override;
namespace std {
class bad_typeid : public exception {
public:
bad_typeid() noexcept;
bad_typeid(const bad_typeid&) noexcept;
bad_typeid& operator=(const bad_typeid&) noexcept;
const char* what() const noexcept override;
};
}bad_typeid() noexcept;
bad_typeid(const bad_typeid&) noexcept;
bad_typeid& operator=(const bad_typeid&) noexcept;
const char* what() const noexcept override;
namespace std {
class exception;
class bad_exception;
class nested_exception;
using terminate_handler = void (*)();
terminate_handler get_terminate() noexcept;
terminate_handler set_terminate(terminate_handler f) noexcept;
[[noreturn]] void terminate() noexcept;
int uncaught_exceptions() noexcept;
using exception_ptr = unspecified;
exception_ptr current_exception() noexcept;
[[noreturn]] void rethrow_exception(exception_ptr p);
template<class E> exception_ptr make_exception_ptr(E e) noexcept;
template <class T> [[noreturn]] void throw_with_nested(T&& t);
template <class E> void rethrow_if_nested(const E& e);
}See also: [except.special].
namespace std {
class exception {
public:
exception() noexcept;
exception(const exception&) noexcept;
exception& operator=(const exception&) noexcept;
virtual ~exception();
virtual const char* what() const noexcept;
};
}exception() noexcept;
exception(const exception& rhs) noexcept;
exception& operator=(const exception& rhs) noexcept;
virtual ~exception();
virtual const char* what() const noexcept;
namespace std {
class bad_exception : public exception {
public:
bad_exception() noexcept;
bad_exception(const bad_exception&) noexcept;
bad_exception& operator=(const bad_exception&) noexcept;
const char* what() const noexcept override;
};
}bad_exception() noexcept;
bad_exception(const bad_exception&) noexcept;
bad_exception& operator=(const bad_exception&) noexcept;
const char* what() const noexcept override;
using terminate_handler = void (*)();
terminate_handler set_terminate(terminate_handler f) noexcept;
terminate_handler get_terminate() noexcept;
[[noreturn]] void terminate() noexcept;
int uncaught_exceptions() noexcept;
using exception_ptr = unspecified;
exception_ptr current_exception() noexcept;
[[noreturn]] void rethrow_exception(exception_ptr p);
template<class E> exception_ptr make_exception_ptr(E e) noexcept;
try {
throw e;
} catch(...) {
return current_exception();
}
namespace std {
class nested_exception {
public:
nested_exception() noexcept;
nested_exception(const nested_exception&) noexcept = default;
nested_exception& operator=(const nested_exception&) noexcept = default;
virtual ~nested_exception() = default;
// access functions
[[noreturn]] void rethrow_nested() const;
exception_ptr nested_ptr() const noexcept;
};
template<class T> [[noreturn]] void throw_with_nested(T&& t);
template <class E> void rethrow_if_nested(const E& e);
}nested_exception() noexcept;
[[noreturn]] void rethrow_nested() const;
exception_ptr nested_ptr() const noexcept;
template <class T> [[noreturn]] void throw_with_nested(T&& t);
template <class E> void rethrow_if_nested(const E& e);
namespace std {
template<class E> class initializer_list {
public:
using value_type = E;
using reference = const E&;
using const_reference = const E&;
using size_type = size_t;
using iterator = const E*;
using const_iterator = const E*;
constexpr initializer_list() noexcept;
constexpr size_t size() const noexcept; // number of elements
constexpr const E* begin() const noexcept; // first element
constexpr const E* end() const noexcept; // one past the last element
};
// [support.initlist.range], initializer list range access
template<class E> constexpr const E* begin(initializer_list<E> il) noexcept;
template<class E> constexpr const E* end(initializer_list<E> il) noexcept;
}constexpr initializer_list() noexcept;
constexpr const E* begin() const noexcept;
constexpr const E* end() const noexcept;
constexpr size_t size() const noexcept;
namespace std {
using va_list = see below;
}
#define va_arg(V, P) see below
#define va_copy(VDST, VSRC) see below
#define va_end(V) see below
#define va_start(V, P) see below
namespace std {
using jmp_buf = see below;
[[noreturn]] void longjmp(jmp_buf env, int val);
}
#define setjmp(env) see below
namespace std {
using sig_atomic_t = see below;
// [support.signal], signal handlers
extern "C" using signal-handler = void(int); // exposition only
signal-handler* signal(int sig, signal-handler* func);
int raise(int sig);
}
#define SIG_DFL see below
#define SIG_ERR see below
#define SIG_IGN see below
#define SIGABRT see below
#define SIGFPE see below
#define SIGILL see below
#define SIGINT see below
#define SIGSEGV see below
#define SIGTERM see belowSubclause | Header(s) | |
Exception classes | <stdexcept> | |
Assertions | <cassert> | |
Error numbers | <cerrno> | |
System error support | <system_error> | |
namespace std {
class logic_error : public exception {
public:
explicit logic_error(const string& what_arg);
explicit logic_error(const char* what_arg);
};
}logic_error(const string& what_arg);
logic_error(const char* what_arg);
namespace std {
class domain_error : public logic_error {
public:
explicit domain_error(const string& what_arg);
explicit domain_error(const char* what_arg);
};
}domain_error(const string& what_arg);
domain_error(const char* what_arg);
namespace std {
class invalid_argument : public logic_error {
public:
explicit invalid_argument(const string& what_arg);
explicit invalid_argument(const char* what_arg);
};
}invalid_argument(const string& what_arg);
invalid_argument(const char* what_arg);
namespace std {
class length_error : public logic_error {
public:
explicit length_error(const string& what_arg);
explicit length_error(const char* what_arg);
};
}length_error(const string& what_arg);
length_error(const char* what_arg);
namespace std {
class out_of_range : public logic_error {
public:
explicit out_of_range(const string& what_arg);
explicit out_of_range(const char* what_arg);
};
}out_of_range(const string& what_arg);
out_of_range(const char* what_arg);
namespace std {
class runtime_error : public exception {
public:
explicit runtime_error(const string& what_arg);
explicit runtime_error(const char* what_arg);
};
}runtime_error(const string& what_arg);
runtime_error(const char* what_arg);
namespace std {
class range_error : public runtime_error {
public:
explicit range_error(const string& what_arg);
explicit range_error(const char* what_arg);
};
}range_error(const string& what_arg);
range_error(const char* what_arg);