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 using-enum-declaration static_assert-declaration template-declaration explicit-specialization deduction-guide alias-declaration opaque-enum-declaration empty-declaration
member-declarator-list: member-declarator member-declarator-list , member-declarator
member-declarator: declarator virt-specifier-seq pure-specifier declarator requires-clause declarator brace-or-equal-initializer identifier attribute-specifier-seq : constant-expression brace-or-equal-initializer
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 };— end example
int a; const int b = 0; struct S { int x1 : 8 = 42; // OK, "= 42" is brace-or-equal-initializer int x2 : 8 { 42 }; // OK, "{ 42 }" is brace-or-equal-initializer int y1 : true ? 8 : a = 42; // OK, brace-or-equal-initializer is absent int y2 : true ? 8 : b = 42; // error: cannot assign to const int int y3 : (true ? 8 : b) = 42; // OK, "= 42" is brace-or-equal-initializer int z : 1 || new int { 0 }; // OK, brace-or-equal-initializer is absent };— end example
struct tnode { char tword[20]; int count; tnode* left; tnode* right; };which contains an array of twenty characters, an integer, and two pointers to objects of the same type.
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; };— end example
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 }— end example
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 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; }— end example
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— end example
complex zz = complex(1,2.3); cprint( complex(7.8,1.2) );— end example
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— end example
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 }— end example
X::X(const X&)if each potentially constructed subobject of a class type M (or array thereof) has a copy constructor whose first parameter is of type const M& or const volatile M&.103
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 }— end example
X& X::operator=(const X&)if
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; };— end example
X& X::operator=(X&&)
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 }— end example
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 }
typedef int I; I* p; p->I::~I();
struct X { operator int(); }; struct Y { operator X(); }; Y a; int b = a; // error: no viable conversion (a.operator X().operator int() not considered) int c = X(a); // OK: a.operator X().operator int()— end example
struct X { operator int(); }; struct Y : X { operator char(); }; void f(Y& a) { if (a) { // error: ambiguous between X::operator int() and Y::operator char() } }— end example
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— end example
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; // error: no conversion function candidate for 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) { } }— end example
&ac.operator int*i; // syntax error: // parsed as: &(ac.operator int *)i // not as: &(ac.operator int)*i
operator int [[noreturn]] (); // error: noreturn attribute applied to a type— end example
struct S { operator auto() const { return 10; } // OK template<class T> operator auto() const { return 1.2; } // error: conversion function template };— end example
struct process { static void reschedule(); }; process& g(); void f() { process::reschedule(); // OK: no object necessary g().reschedule(); // g() is called }— end example
int g(); struct X { static int g(); }; struct Y : X { static int i; }; int Y::i = g(); // equivalent to Y::g();— end example
class process { static process* run_chain; static process* running; }; process* process::running = get_main(); process* process::run_chain = running;
identifier attribute-specifier-seq : constant-expression brace-or-equal-initializerspecifies a bit-field.
enum BOOL { FALSE=0, TRUE=1 }; struct A { BOOL b:1; }; A a; void f() { a.b = TRUE; if (a.b == TRUE) // yields true { /* ... */ } }— end example
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— end example
struct enclose { struct inner { static int x; void f(int i); }; }; int enclose::inner::x = 1; void enclose::inner::f(int i) { /* ... */ }— end example
class E { class I1; // forward declaration of nested class class I2; class I1 { }; // definition of nested class }; class E::I2 { }; // definition of nested class— end example
struct X { typedef int I; class Y { /* ... */ }; I a; }; I b; // error Y c; // error X::Y d; // OK X::I e; // OK— end example