[class] (original) (raw)

11 Classes [class]

11.1 Preamble [class.pre]

A class is a type.

Its name becomes a class-name ([class.name]) within its scope.

An object of a class consists of a (possibly empty) sequence of members and base class objects.

class-property-specifier:
final
trivially_relocatable_if_eligible
replaceable_if_eligible

class-key:
class
struct
union

A class-specifier whoseclass-head omits theclass-head-name defines an unnamed class.

[Note 1:

An unnamed class thus can't be final.

— _end note_]

Otherwise, the class-name is an identifier; it is not looked up, and the class-specifier introduces it.

The component name of theclass-name is also bound in the scope of the class (template) itself; this is known as the injected-class-name.

For purposes of access checking, the injected-class-name is treated as if it were a public member name.

A class-specifier is commonly referred to as a class definition.

A class is considered defined after the closing brace of itsclass-specifier has been seen even though its member functions are in general not yet defined.

If its class-name is an identifier, the class-specifier shall correspond to one or more declarations nominable in the class, class template, or namespace to which thenested-name-specifier refers; they shall all have the same target scope, and the target scope of theclass-specifier is that scope.

[Example 1: namespace N { template<class> struct A { struct B;};} using N::A;template<class T> struct A<T>::B {}; template<> struct A<void> {}; — _end example_]

[Note 2:

The class-key determines whether the class is a union ([class.union]) and whether access is public or private by default ([class.access]).

A union holds the value of at most one data member at a time.

— _end note_]

Each class-property-specifier shall appear at most once within a single class-property-specifier-seq.

Whenever a class-key is followed by a class-head-name, the identifier final, trivially_relocatable_if_eligible, or replaceable_if_eligible, and a colon or left brace, the identifier is interpreted as a class-property-specifier.

[Example 2: struct A;struct A final {}; struct X { struct C { constexpr operator int() { return 5; } };struct B trivially_relocatable_if_eligible : C{};}; — _end example_]

If a class is marked with the class-property-specifier final and that class appears as a class-or-decltypein a base-clause ([class.derived]), the program is ill-formed.

[Note 3:

Complete objects of class type have nonzero size.

Base class subobjects and members declared with the no_unique_address attribute ([dcl.attr.nouniqueaddr]) are not so constrained.

— _end note_]

[Note 4:

Class objects can be assigned ([over.assign], [class.copy.assign]), passed as arguments to functions ([dcl.init], [class.copy.ctor]), and returned by functions (except objects of classes for which copying or moving has been restricted; see [dcl.fct.def.delete] and [class.access]).

Other plausible operators, such as equality comparison, can be defined by the user; see [over.oper].

— _end note_]

11.2 Properties of classes [class.prop]

A trivially copyable class is a class:

A class C is default-movable if

A class is eligible for trivial relocation unless it

except that it is implementation-defined whether an otherwise-eligible union having one or more subobjects of polymorphic class type is eligible for trivial relocation.

A class C is a trivially relocatable classif it is eligible for trivial relocation and

[Note 1:

A class with const-qualified or reference non-static data members can be trivially relocatable.

— _end note_]

A class C is eligible for replacement unless

A class C is a replaceable class if it is eligible for replacement and

[Note 2:

Accessibility of the special member functions is not considered when establishing trivial relocatability or replaceability.

— _end note_]

[Note 3:

Not all trivially copyable classes are trivially relocatable or replaceable.

— _end note_]

A class S is a standard-layout class if it:

[Example 1: struct B { int i; }; struct C : B { }; struct D : C { }; struct E : D { char : 4; }; struct Q {};struct S : Q { };struct T : Q { };struct U : S, T { }; — _end example_]

A standard-layout struct is a standard-layout class defined with the class-key struct or theclass-key class.

A standard-layout union is a standard-layout class defined with theclass-key union.

[Note 5:

Standard-layout classes are useful for communicating with code written in other programming languages.

— _end note_]

[Example 2: struct N { int i;int j;virtual ~N();};struct T { int i;private: int j;};struct SL { int i;int j;~SL();};struct POD { int i;int j;}; — _end example_]

A class S is an implicit-lifetime class if

11.3 Class names [class.name]

A class definition introduces a new type.

[Example 1:

struct X { int a; };struct Y { int a; }; X a1; Y a2;int a3;declares three variables of three different types.

This implies thata1 = a2; a1 = a3; are type mismatches, and thatint f(X);int f(Y); declare overloads ([over]) named f and not simply a single function f twice.

For the same reason,struct S { int a; };struct S { int a; }; is ill-formed because it defines S twice.

— _end example_]

[Note 1:

It can be necessary to use an elaborated-type-specifierto refer to a class that belongs to a scope in which its name is also bound to a variable, function, or enumerator ([basic.lookup.elab]).

[Example 2: struct stat { }; stat gstat; int stat(struct stat*); void f() { struct stat* ps; stat(ps); } — _end example_]

[Example 3: struct s { int a; };void g() { struct s; s* p; struct s { char* p; }; struct s; } — _end example_]

Such declarations allow definition of classes that refer to each other.

[Example 4: class Vector;class Matrix { friend Vector operator*(const Matrix&, const Vector&);};class Vector { friend Vector operator*(const Matrix&, const Vector&);};

Declaration of friends is described in [class.friend], operator functions in [over.oper].

— _end example_]

— _end note_]

[Note 2:

It differs from a class declaration in that it can refer to an existing class of the given name.

— _end note_]

[Example 5: struct s { int a; };void g(int s) { struct s* p = new struct s; p->a = s; } — _end example_]

[Note 3:

[Example 6:

class A * A;first specifies A to be the name of a class and then redefines it as the name of a pointer to an object of that class.

This means that the elaborated form class A must be used to refer to the class.

Such artistry with names can be confusing and is best avoided.

— _end example_]

— _end note_]

11.4 Class members [class.mem]

11.4.1 General [class.mem.general]

virt-specifier:
override
final

[Note 1:

If the member declaration acquires a function type through template instantiation, the program is ill-formed; see [temp.spec.general].

— _end note_]

The member-specification in a class definition declares the full set of members of the class; no member can be added elsewhere.

A direct member of a class X is a member of Xthat was first declared within the member-specification of X, including anonymous union members ([class.union.anon]) and direct members thereof.

Members of a class are data members, member functions ([class.mfct]), nested types, enumerators, and member templates ([temp.mem]) and specializations thereof.

[Note 2:

A specialization of a static data member template is a static data member.

A specialization of a member function template is a member function.

A specialization of a member class template is a nested class.

— _end note_]

For any other member-declaration, each declared entity that is not an unnamed bit-fieldis a member of the class, and each such member-declarationshall either declare at least one member name of the class or declare at least one unnamed bit-field.

A data member is a non-function member introduced by amember-declarator.

A member function is a member that is a function.

Nested types are classes ([class.name], [class.nest]) and enumerations ([dcl.enum]) declared in the class and arbitrary types declared as members by use of a typedef declaration ([dcl.typedef]) or alias-declaration.

The enumerators of an unscoped enumeration defined in the class are members of the class.

A data member or member function may be declared static in its member-declaration, in which case it is a static member (see [class.static]) (a static data member ([class.static.data]) orstatic member function ([class.static.mfct]), respectively) of the class.

Any other data member or member function is a non-static member(a non-static data member ornon-static member function ([class.mfct.non.static]), respectively).

[Note 3:

A non-static data member of non-reference type is a member subobject of a class object.

— _end note_]

A member shall not be declared twice in themember-specification, except that

[Note 4:

A single name can denote several member functions provided their types are sufficiently different ([basic.scope.scope]).

— _end note_]

A redeclaration of a class member outside its class definition shall be a definition, an explicit specialization, or an explicit instantiation ([temp.expl.spec], [temp.explicit]).

The member shall not be a non-static data member.

[Note 5:

A complete-class context of a nested class is also a complete-class context of any enclosing class, if the nested class is defined within the member-specification of the enclosing class.

— _end note_]

A class C is complete at a program point Pif the definition of C is reachable from P ([module.reach]) or if P is in a complete-class context of C.

Otherwise, C is incomplete at P.

If a member-declaration matches the syntactic requirements of friend-type-declaration, it is a friend-type-declaration.

[Example 1: struct S { using T = void(); T * p = 0; virtual T f = 0; }; — _end example_]

[Example 2: int a;const int b = 0;struct S { int x1 : 8 = 42; int x2 : 8 { 42 }; int y1 : true ? 8 : a = 42; int y2 : true ? 8 : b = 42; int y3 : (true ? 8 : b) = 42; int z : 1 || new int { 0 }; }; — _end example_]

(For static data members, see [class.static.data]; for non-static data members, see [class.base.init] and [dcl.init.aggr]).

A brace-or-equal-initializer for a non-static data memberspecifies a default member initializer for the member, and shall not directly or indirectly cause the implicit definition of a defaulted default constructor for the enclosing class or the exception specification of that constructor.

An immediate invocation ([expr.const]) that is a potentially-evaluated subexpression ([intro.execution]) of a default member initializer is neither evaluated nor checked for whether it is a constant expression at the point where the subexpression appears.

Within a class definition, a member shall not be declared with the thread_local storage-class-specifier unless also declared static.

Apure-specifier shall be used only in the declaration of avirtual functionthat is not a friend declaration.

The optional attribute-specifier-seq in a member-declarationappertains to each of the entities declared by the member-declarators; it shall not appear if the optional member-declarator-list is omitted.

A virt-specifier-seq shall contain at most one of eachvirt-specifier.

A virt-specifier-seqshall appear only in the first declaration of a virtual member function ([class.virtual]).

The type of a non-static data member shall not be an incomplete type ([basic.types.general]), an abstract class type ([class.abstract]), or a (possibly multidimensional) array thereof.

[Note 6:

In particular, a class C cannot contain a non-static member of class C, but it can contain a pointer or reference to an object of class C.

— _end note_]

[Note 7:

See [expr.prim.id] for restrictions on the use of non-static data members and non-static member functions.

— _end note_]

[Note 8:

The type of a non-static member function is an ordinary function type, and the type of a non-static data member is an ordinary object type.

There are no special member function types or data member types.

— _end note_]

[Example 3:

A simple example of a class definition isstruct 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.

Once this definition has been given, the declarationtnode s, *sp;declares s to be a tnode and sp to be a pointer to a tnode.

With these declarations, sp->count refers to the count member of the object to which sp points;s.left refers to the left subtree pointer of the objects; and s.right->tword[0] refers to the initial character of the tword member of the right subtree of s.

— _end example_]

[Note 9:

Non-variant non-static data members of non-zero size ([intro.object]) are allocated so that later members have higher addresses within a class object ([expr.rel]).

Implementation alignment requirements can cause two adjacent members not to be allocated immediately after each other; so can requirements for space for managing virtual functions ([class.virtual]) and virtual base classes ([class.mi]).

— _end note_]

If T is the name of a class, then each of the following shall have a name different from T:

In addition, if class T has a user-declaredconstructor, every non-static data member of classT shall have a name different from T.

The common initial sequence of two standard-layout struct ([class.prop]) types is the longest sequence of non-static data members and bit-fields in declaration order, starting with the first such entity in each of the structs, such that

[Example 4: 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; };

The common initial sequence of A and B comprises all members of either class.

The common initial sequence of A and C and of A and D comprises the first member in each case.

The common initial sequence of A and E is empty.

— _end example_]

Two standard-layout struct ([class.prop]) types arelayout-compatible classes if their common initial sequence comprises all members and bit-fields of both classes ([basic.types]).

Two standard-layout unions are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in any order) have layout-compatible types ([basic.types.general]).

In a standard-layout union with an active memberof struct type T1, it is permitted to read a non-static data member m of another union member of struct type T2provided m is part of the common initial sequence of T1 and T2; the behavior is as if the corresponding member of T1 were nominated.

[Example 5: struct T1 { int a, b; };struct T2 { int c; double d; };union U { T1 t1; T2 t2; };int f() { U u = { { 1, 2 } }; return u.t2.c; } — _end example_]

[Note 11:

Reading a volatile object through a glvalue of non-volatile type has undefined behavior ([dcl.type.cv]).

— _end note_]

If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member if that member is not a bit-field.

Its address is also the same as the address of each of its base class subobjects.

[Note 12:

There can therefore be unnamed padding within a standard-layout struct object inserted by an implementation, but not at its beginning, as necessary to achieve appropriate alignment.

— _end note_]

11.4.2 Member functions [class.mfct]

If a member function is attached to the global module and is defined ([dcl.fct.def]) in its class definition, it is inline ([dcl.inline]).

[Note 1:

A member function is also inline if it is declaredinline, constexpr, or consteval.

— _end note_]

[Example 1: struct X { typedef int T;static T count;void f(T);};void X::f(T t = count) { }

The definition of the member function f of class X inhabits the global scope; the notation X​::​f indicates that the function fis a member of class X and in the scope of class X.

In the function definition, the parameter type T refers to the typedef member T declared in class X and the default argument count refers to the static data member countdeclared in class X.

— _end example_]

Member functions of a local class shall be defined inline in their class definition, if they are defined at all.

[Note 2:

A member function can be declared (but not defined) using a typedef for a function type.

The resulting member function has exactly the same type as it would have if the function declarator were provided explicitly, see [dcl.fct] and [temp.arg].

[Example 2: typedef void fv();typedef void fvc() const;struct S { fv memfunc1; void memfunc2(); fvc memfunc3; }; fv S::* pmfv1 = &S::memfunc1; fv S::* pmfv2 = &S::memfunc2; fvc S::* pmfv3 = &S::memfunc3; — _end example_]

— _end note_]

11.4.3 Non-static member functions [class.mfct.non.static]

A non-static member function may be called for an object of its class type, or for an object of a class derived ([class.derived]) from its class type, using the class member access syntax ([expr.ref], [over.match.call]).

A non-static member function may also be called directly using the function call syntax ([expr.call], [over.match.call]) from within its class or a class derived from its class, or a member thereof, as described below.

An implicit object member function may be declared virtual ([class.virtual]) or pure virtual ([class.abstract]).

11.4.4 Special member functions [special]

Default constructors ([class.default.ctor]), copy constructors, move constructors ([class.copy.ctor]), copy assignment operators, move assignment operators ([class.copy.assign]), and prospective destructors ([class.dtor]) arespecial member functions.

[Note 1:

The implementation will implicitly declare these member functions for some class types when the program does not explicitly declare them.

— _end note_]

An implicitly-declared special member function is declared at the closing} of the class-specifier.

Programs shall not define implicitly-declared special member functions.

Programs may explicitly refer to implicitly-declared special member functions.

[Example 1:

A program may explicitly call or form a pointer to member to an implicitly-declared special member function.

struct A { }; struct B : A { B& operator=(const B &);}; B& B::operator=(const B& s) { this->A::operator=(s); return *this;} — _end example_]

[Note 2:

The special member functions affect the way objects of class type are created, copied, moved, and destroyed, and how values can be converted to values of other types.

Often such special member functions are called implicitly.

— _end note_]

Special member functions obey the usual access rules ([class.access]).

[Example 2:

Declaring a constructor protected ensures that only derived classes and friends can create objects using it.

— _end example_]

Two special member functions are of the same kind if

An eligible special member function is a special member function for which:

For a class, its non-static data members, its non-virtual direct base classes, and, if the class is not abstract ([class.abstract]), its virtual base classes are called its potentially constructed subobjects.

11.4.5 Constructors [class.ctor]

11.4.5.1 General [class.ctor.general]

Constructors do not have names.

[Example 1: struct S { S(); }; S::S() { } — _end example_]

A constructor is used to initialize objects of its class type.

[Note 1:

Because constructors do not have names, they are never found during unqualified name lookup; however an explicit type conversion using the functional notation ([expr.type.conv]) will cause a constructor to be called to initialize an object.

The syntax looks like an explicit call of the constructor.

— _end note_]

[Example 2: complex zz = complex(1,2.3); cprint( complex(7.8,1.2) ); — _end example_]

[Note 2:

For initialization of objects of class type see [class.init].

— _end note_]

An object created in this way is unnamed.

[Note 4:

Explicit constructor calls do not yield lvalues, see [basic.lval].

— _end note_]

[Note 5:

Some language constructs have special semantics when used during construction; see [class.base.init] and [class.cdtor].

— _end note_]

A constructor can be invoked for aconst,volatileorconst volatileobject.

constandvolatilesemantics ([dcl.type.cv]) are not applied on an object under construction.

They come into effect when the constructor for the most derived object ([intro.object]) ends.

The address of a constructor shall not be taken.

[Note 6:

A return statement in the body of a constructor cannot specify a return value ([stmt.return]).

— _end note_]

A constructor shall not be a coroutine.

A constructor shall not have an explicit object parameter ([dcl.fct]).

11.4.5.2 Default constructors [class.default.ctor]

A default constructor for a class Xis a constructor of class Xfor which each parameter that is not a function parameter pack has a default argument (including the case of a constructor with no parameters).

If there is no user-declared constructor or constructor template for classX, a non-explicit constructor having no parameters is implicitly declared as defaulted ([dcl.fct.def]).

An implicitly-declared default constructor is an inline public member of its class.

A defaulted default constructor for class X is defined as deleted if

A default constructor for a class X istrivialif it is not user-provided and if

Otherwise, the default constructor isnon-trivial.

If a default constructor of a union-like class X is trivial, then for each union Uthat is either X or an anonymous union member of X, if the first variant member, if any, of Uhas implicit-lifetime type ([basic.types.general]), the default constructor of X begins the lifetime of that member if it is not the active member of its union.

[Note 1:

It is already the active member if U was value-initialized.

— _end note_]

Otherwise, an implicitly-defined ([dcl.fct.def.default]) default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with noctor-initializer ([class.base.init]) and an emptycompound-statement.

If that user-written default constructor would be ill-formed, the program is ill-formed.

If that user-written default constructor would be constexpr-suitable ([dcl.constexpr]), the implicitly-defined default constructor is constexpr.

Before the defaulted default constructor for a class is implicitly defined, all the non-user-provided default constructors for its base classes and its non-static data members are implicitly defined.

[Note 2:

An implicitly-declared default constructor has an exception specification ([except.spec]).

An explicitly-defaulted definition might have an implicit exception specification, see [dcl.fct.def].

— _end note_]

[Note 3:

A default constructor is implicitly invoked to initialize a class object when no initializer is specified ([dcl.init.general]).

Such a default constructor needs to be accessible ([class.access]).

— _end note_]

[Note 4:

[class.base.init] describes the order in which constructors for base classes and non-static data members are called and describes how arguments can be specified for the calls to these constructors.

— _end note_]

11.4.5.3 Copy/move constructors [class.copy.ctor]

A non-template constructor for classXis a copy constructor if its first parameter is of typeX&,const X&,volatile X&orconst volatile X&, and either there are no other parameters or else all other parameters have default arguments ([dcl.fct.default]).

[Example 1:

X​::​X(const X&)andX​::​X(X&,int=1)are copy constructors.

struct X { X(int); X(const X&, int = 1);}; X a(1); X b(a, 0); X c = b; — _end example_]

A non-template constructor for class X is a move constructor if its first parameter is of type X&&, const X&&,volatile X&&, or const volatile X&&, and either there are no other parameters or else all other parameters have default arguments ([dcl.fct.default]).

[Example 2:

Y​::​Y(Y&&) is a move constructor.

struct Y { Y(const Y&); Y(Y&&);};extern Y f(int); Y d(f(1)); Y e = d; — _end example_]

[Note 1:

All forms of copy/move constructor can be declared for a class.

[Example 3: struct X { X(const X&); X(X&); X(X&&); X(const X&&); }; — _end example_]

— _end note_]

[Note 2:

If a classXonly has a copy constructor with a parameter of typeX&, an initializer of typeconst Xorvolatile Xcannot initialize an object of typecv X.

[Example 4: struct X { X(); X(X&); };const X cx; X x = cx; — _end example_]

— _end note_]

A declaration of a constructor for a classXis ill-formed if its first parameter is of typecv Xand either there are no other parameters or else all other parameters have default arguments.

A member function template is never instantiated to produce such a constructor signature.

[Example 5: struct S { template<typename T> S(T); S();}; S g;void h() { S a(g); } — _end example_]

If the class definition does not explicitly declare a copy constructor, a non-explicit one is declared implicitly.

If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defaulted ([dcl.fct.def]).

The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor ([depr.impldec]).

The implicitly-declared copy constructor for a classXwill have the formX::X(const X&) if each potentially constructed subobject of a class typeM(or array thereof) has a copy constructor whose first parameter is of typeconst M&orconst volatile M&.89

Otherwise, the implicitly-declared copy constructor will have the formX::X(X&)

If the definition of a class X does not explicitly declare a move constructor, a non-explicit one will be implicitly declared as defaulted if and only if

[Note 3:

When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor might instead invoke a copy constructor.

— _end note_]

The implicitly-declared move constructor for class X will have the formX::X(X&&)

An implicitly-declared copy/move constructor is an inline public member of its class.

A defaulted copy/​move constructor for a classX is defined as deleted ([dcl.fct.def.delete]) if X has:

[Note 4:

A defaulted move constructor that is defined as deleted is ignored by overload resolution ([over.match], [over.over]).

Such a constructor would otherwise interfere with initialization from an rvalue which can use the copy constructor instead.

— _end note_]

A copy/move constructor for classXis trivial if it is not user-provided and if

otherwise the copy/move constructor isnon-trivial.

Before the defaulted copy/move constructor for a class is implicitly defined, all non-user-provided copy/move constructors for its potentially constructed subobjects are implicitly defined.

[Note 6:

An implicitly-declared copy/move constructor has an implied exception specification ([except.spec]).

— _end note_]

The implicitly-defined copy/move constructor for a non-union classXperforms a memberwise copy/move of its bases and members.

[Note 7:

Default member initializers of non-static data members are ignored.

— _end note_]

The order of initialization is the same as the order of initialization of bases and members in a user-defined constructor (see [class.base.init]).

Let x be either the parameter of the constructor or, for the move constructor, an xvalue referring to the parameter.

Each base or non-static data member is copied/moved in the manner appropriate to its type:

Virtual base class subobjects shall be initialized only once by the implicitly-defined copy/move constructor (see [class.base.init]).

The implicitly-defined copy/move constructor for a unionX copies the object representation ([basic.types.general]) of X.

For each object nested within ([intro.object]) the object that is the source of the copy, a corresponding object o nested within the destination is identified (if the object is a subobject) or created (otherwise), and the lifetime of o begins before the copy is performed.

11.4.6 Copy/move assignment operator [class.copy.assign]

A user-declared copy assignment operator X​::​operator= is a non-static non-template member function of class X with exactly one non-object parameter of type X, X&, const X&,volatile X&, or const volatile X&.90

[Note 1:

More than one form of copy assignment operator can be declared for a class.

— _end note_]

[Note 2:

If a classXonly has a copy assignment operator with a non-object parameter of typeX&, an expression of type constXcannot be assigned to an object of typeX.

[Example 1: struct X { X(); X& operator=(X&);};const X cx; X x;void f() { x = cx; } — _end example_]

— _end note_]

If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly.

If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defaulted ([dcl.fct.def]).

The latter case is deprecated if the class has a user-declared copy constructor or a user-declared destructor ([depr.impldec]).

The implicitly-declared copy assignment operator for a classXwill have the formX& X::operator=(const X&) if

Otherwise, the implicitly-declared copy assignment operator will have the formX& X::operator=(X&)

A user-declared move assignment operator X​::​operator= is a non-static non-template member function of class X with exactly one non-object parameter of type X&&, const X&&, volatile X&&, orconst volatile X&&.

[Note 3:

More than one form of move assignment operator can be declared for a class.

— _end note_]

If the definition of a class X does not explicitly declare a move assignment operator, one will be implicitly declared as defaulted if and only if

[Example 2:

The class definitionstruct 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.

The move assignment operator may be explicitly defaulted.

struct S { int a; S& operator=(const S&) = default; S& operator=(S&&) = default;}; — _end example_]

The implicitly-declared move assignment operator for a class X will have the formX& X::operator=(X&&)

The implicitly-declared copy/move assignment operator for classXhas the return typeX&.

An implicitly-declared copy/move assignment operator is an inline public member of its class.

A defaulted copy/move assignment operator for class X is defined as deleted if X has:

[Note 4:

A defaulted move assignment operator that is defined as deleted is ignored by overload resolution ([over.match], [over.over]).

— _end note_]

Because a copy/move assignment operator is implicitly declared for a class if not declared by the user, a base class copy/move assignment operator is always hidden by the corresponding assignment operator of a derived class ([over.assign]).

[Note 5:

A using-declaration in a derived class Cthat names an assignment operator from a base class never suppresses the implicit declaration of an assignment operator of C, even if the base class assignment operator would be a copy or move assignment operator if declared as a member of C.

— _end note_]

A copy/move assignment operator for classXis trivial if it is not user-provided and if

otherwise the copy/move assignment operator isnon-trivial.

Before the defaulted copy/move assignment operator for a class is implicitly defined, all non-user-provided copy/move assignment operators for its direct base classes and its non-static data members are implicitly defined.

[Note 6:

An implicitly-declared copy/move assignment operator has an implied exception specification ([except.spec]).

— _end note_]

The implicitly-defined copy/move assignment operator for a non-union class X performs memberwise copy/move assignment of its subobjects.

The direct base classes of X are assigned first, in the order of their declaration in thebase-specifier-list, and then the immediate non-static data members ofX are assigned, in the order in which they were declared in the class definition.

Let x be either the parameter of the function or, for the move operator, an xvalue referring to the parameter.

Each subobject is assigned in the manner appropriate to its type:

It is unspecified whether subobjects representing virtual base classes are assigned more than once by the implicitly-defined copy/move assignment operator.

[Example 3: struct V { };struct A : virtual V { };struct B : virtual V { };struct C : B, A { };

It is unspecified whether the virtual base class subobjectVis assigned twice by the implicitly-defined copy/move assignment operator forC.

— _end example_]

The implicitly-defined copy/move assignment operator for a union X copies the object representation ([basic.types.general]) of X.

If the source and destination of the assignment are not the same object, then for each object nested within ([intro.object]) the object that is the source of the copy, a corresponding object o nested within the destination is created, and the lifetime of o begins before the copy is performed.

The implicitly-defined copy/move assignment operator for a class returns the object for which the assignment operator is invoked, that is, the object assigned to.

11.4.7 Destructors [class.dtor]

If a class has no user-declared prospective destructor, a prospective destructor is implicitly declared as defaulted ([dcl.fct.def]).

An implicitly-declared prospective destructor is an inline public member of its class.

An implicitly-declared prospective destructor for a class X will have the form~X()

At the end of the definition of a class, overload resolution is performed among the prospective destructors declared in that class with an empty argument list to select the destructor for the class, also known as the selected destructor.

The program is ill-formed if overload resolution fails.

Destructor selection does not constitute a reference to, or odr-use ([basic.def.odr]) of, the selected destructor, and in particular, the selected destructor may be deleted ([dcl.fct.def.delete]).

The address of a destructor shall not be taken.

[Note 1:

A return statement in the body of a destructor cannot specify a return value ([stmt.return]).

— _end note_]

A destructor can be invoked for aconst,volatileorconst volatileobject.

constandvolatilesemantics ([dcl.type.cv]) are not applied on an object under destruction.

They stop being in effect when the destructor for the most derived object ([intro.object]) starts.

[Note 2:

A declaration of a destructor that does not have a noexcept-specifierhas the same exception specification as if it had been implicitly declared ([except.spec]).

— _end note_]

A defaulted destructor for a classX is defined as deleted if

A destructor for a class X is trivial if it is not user-provided and if

Otherwise, the destructor isnon-trivial.

A defaulted destructor is a constexpr destructor if it is constexpr-suitable ([dcl.constexpr]).

Before a defaulted destructor for a class is implicitly defined, all the non-user-provided destructors for its base classes and its non-static data members are implicitly defined.

A prospective destructor can be declared virtual ([class.virtual]) and with a pure-specifier ([class.abstract]).

If the destructor of a class is virtual and any objects of that class or any derived class are created in the program, the destructor shall be defined.

[Note 3:

Some language constructs have special semantics when used during destruction; see [class.cdtor].

— _end note_]

After executing the body of the destructor and destroying any objects with automatic storage duration allocated within the body, a destructor for classXcalls the destructors forX's direct non-variant non-static data members other than anonymous unions, the destructors forX's non-virtual direct base classes and, ifXis the most derived class ([class.base.init]), its destructor calls the destructors forX's virtual base classes.

All destructors are called as if they were referenced with a qualified name, that is, ignoring any possible virtual overriding destructors in more derived classes.

Bases and members are destroyed in the reverse order of the completion of their constructor (see [class.base.init]).

[Note 4:

Areturnstatement ([stmt.return]) in a destructor might not directly return to the caller; before transferring control to the caller, the destructors for the members and bases are called.

— _end note_]

Destructors for elements of an array are called in reverse order of their construction (see [class.init]).

A destructor is invoked implicitly

In each case, the context of the invocation is the context of the construction of the object.

[Note 5:

An array of class type contains several subobjects for each of which the destructor is invoked.

— _end note_]

A destructor can also be invoked explicitly.

A program is ill-formed if a destructor that is potentially invoked is deleted or not accessible from the context of the invocation.

At the point of definition of a virtual destructor (including an implicit definition), the non-array deallocation function is determined as if for the expression delete this appearing in a non-virtual destructor of the destructor's class (see [expr.delete]).

If the lookup fails or if the deallocation function has a deleted definition ([dcl.fct.def]), the program is ill-formed.

[Note 6:

This assures that a deallocation function corresponding to the dynamic type of an object is available for thedelete-expression ([class.free]).

— _end note_]

In an explicit destructor call, the destructor is specified by a~followed by atype-name or computed-type-specifierthat denotes the destructor's class type.

The invocation of a destructor is subject to the usual rules for member functions ([class.mfct]); that is, if the object is not of the destructor's class type and not of a class derived from the destructor's class type (including when the destructor is invoked via a null pointer value), the program has undefined behavior.

[Note 7:

Invoking delete on a null pointer does not call the destructor; see [expr.delete].

— _end note_]

[Example 1: 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(); B_ptr->~B(); B_ptr->~B_alias(); B_ptr->B_alias::~B(); B_ptr->B_alias::~B_alias(); } — _end example_]

[Note 9:

Explicit calls of destructors are rarely needed.

One use of such calls is for objects placed at specific addresses using a placementnew-expression.

Such use of explicit placement and destruction of objects can be necessary to cope with dedicated hardware resources and for writing memory management facilities.

[Example 2: void* operator new(std::size_t, void* p) { return p; } struct X { X(int);~X();};void f(X* p);void g() { char* buf = new char[sizeof(X)]; X* p = new(buf) X(222); f(p); p->X::~X(); } — _end example_]

— _end note_]

Once a destructor is invoked for an object, the object's lifetime ends; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended ([basic.life]).

[Example 3:

If the destructor for an object with automatic storage duration is explicitly invoked, and the block is subsequently left in a manner that would ordinarily invoke implicit destruction of the object, the behavior is undefined.

— _end example_]

[Note 10:

The notation for explicit call of a destructor can be used for any scalar type name ([expr.prim.id.dtor]).

Allowing this makes it possible to write code without having to know if a destructor exists for a given type.

For example:typedef int I; I* p; p->I::~I();

— _end note_]

A destructor shall not be a coroutine.

11.4.8 Conversions [class.conv]

11.4.8.1 General [class.conv.general]

Type conversions of class objects can be specified by constructors and by conversion functions.

User-defined conversions are applied only where they are unambiguous ([class.member.lookup], [class.conv.fct]).

Conversions obey the access control rules ([class.access]).

Access control is applied after ambiguity resolution ([basic.lookup]).

[Note 1:

See [over.match] for a discussion of the use of conversions in function calls.

— _end note_]

At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.

[Example 1: struct X { operator int();};struct Y { operator X();}; Y a;int b = a; int c = X(a); — _end example_]

11.4.8.2 Conversion by constructor [class.conv.ctor]

A constructor that is not explicit ([dcl.fct.spec]) specifies a conversion from the types of its parameters (if any) to the type of its class.

[Example 1: struct X { X(int); X(const char*, int = 0); X(int, int);};void f(X arg) { X a = 1; X b = "Jessie"; a = 2; f(3); f({1, 2}); } — _end example_]

[Note 1:

An explicit constructor constructs objects just like non-explicit constructors, but does so only where the direct-initialization syntax ([dcl.init]) or where casts ([expr.static.cast], [expr.cast]) are explicitly used; see also [over.match.copy].

A default constructor can be an explicit constructor; such a constructor will be used to perform default-initialization or value-initialization ([dcl.init]).

[Example 2: struct Z { explicit Z();explicit Z(int);explicit Z(int, int);}; Z a; Z b{}; Z c = {}; Z a1 = 1; Z a3 = Z(1); Z a2(1); Z* p = new Z(1); Z a4 = (Z)1; Z a5 = static_cast<Z>(1); Z a6 = { 3, 4 }; — _end example_]

— _end note_]

11.4.8.3 Conversion functions [class.conv.fct]

A conversion function shall have no non-object parameters and shall be a non-static member function of a class or class template X; its declared return type is the conversion-type-id and it specifies a conversion from X to the type specified by the conversion-type-id, interpreted as a type-id ([dcl.name]).

[Note 1:

A conversion function is never invoked for implicit or explicit conversions of an object to the same object type (or a reference to it), to a base class of that type (or a reference to it), or to cv void.

Even though never directly called to perform a conversion, such conversion functions can be declared and can potentially be reached through a call to a virtual conversion function in a base class.

— _end note_]

[Example 1: struct X { operator int();operator auto() -> short; };void f(X a) { int i = int(a); i = (int)a; i = a;}

In all three cases the value assigned will be converted byX​::​operator int().

— _end example_]

A conversion function may be explicit ([dcl.fct.spec]), in which case it is only considered as a user-defined conversion for direct-initialization ([dcl.init]).

Otherwise, user-defined conversions are not restricted to use in assignments and initializations.

[Example 2: class Y { };struct Z { explicit operator Y() const;};void h(Z z) { Y y1(z); Y y2 = z; Y y3 = (Y)z; } void g(X a, X b) { int i = (a) ? 1+a : 0;int j = (a&&b) ? a+b : i;if (a) { } } — _end example_]

Theconversion-type-idshall not represent a function type nor an array type.

Theconversion-type-idin aconversion-function-idis the longest sequence of tokens that could possibly form a conversion-type-id.

[Note 2:

This prevents ambiguities between the declarator operator * and its expression counterparts.

[Example 3: &ac.operator int*i;

The * is the pointer declarator and not the multiplication operator.

— _end example_]

This rule also prevents ambiguities for attributes.

[Example 4: operator int [[noreturn]] (); — _end example_]

— _end note_]

[Note 3:

A conversion function in a derived class hides only conversion functions in base classes that convert to the same type.

A conversion function template with a dependent return type hides only templates in base classes that correspond to it ([class.member.lookup]); otherwise, it hides and is hidden as a non-template function.

Function overload resolution ([over.match.best]) selects the best conversion function to perform the conversion.

[Example 5: struct X { operator int();};struct Y : X { operator char();};void f(Y& a) { if (a) { } } — _end example_]

— _end note_]

Conversion functions can be virtual.

A conversion function template shall not have a deduced return type ([dcl.spec.auto]).

[Example 6: struct S { operator auto() const { return 10; } template<class T> operator auto() const { return 1.2; } }; — _end example_]

11.4.9 Static members [class.static]

11.4.9.1 General [class.static.general]

A static member s of class X may be referred to using the qualified-id expression X​::​s; it is not necessary to use the class member access syntax ([expr.ref]) to refer to a static member.

A static member may be referred to using the class member access syntax, in which case the object expression is evaluated.

[Example 1: struct process { static void reschedule();}; process& g();void f() { process::reschedule(); g().reschedule(); } — _end example_]

Static members obey the usual class member access rules ([class.access]).

When used in the declaration of a class member, the static specifier shall only be used in the member declarations that appear within the member-specification of the class definition.

[Note 1:

It cannot be specified in member declarations that appear in namespace scope.

— _end note_]

11.4.9.2 Static member functions [class.static.mfct]

[Note 1:

The rules described in [class.mfct] apply to static member functions.

— _end note_]

[Note 2:

A static member function does not have a thispointer ([expr.prim.this]).

A static member function cannot be qualified with const,volatile, or virtual ([dcl.fct]).

— _end note_]

11.4.9.3 Static data members [class.static.data]

A static data member is not part of the subobjects of a class.

If a static data member is declared thread_local there is one copy of the member per thread.

If a static data member is not declaredthread_local there is one copy of the data member that is shared by all the objects of the class.

A static data member shall not be mutable ([dcl.stc]).

A static data member shall not be a direct member ([class.mem]) of an unnamed ([class.pre]) or local ([class.local]) class or of a (possibly indirectly) nested class ([class.nest]) thereof.

The declaration of a non-inline static data member in its class definition is not a definition and may be of an incomplete type other thancv void.

[Example 1: class process { static process* run_chain;static process* running;}; process* process::running = get_main(); process* process::run_chain = running;

The definition of the static data member run_chain of classprocess inhabits the global scope; the notationprocess​::​run_chain indicates that the member run_chainis a member of class process and in the scope of classprocess.

In the static data member definition, theinitializer expression refers to the static data member running of class process.

— _end example_]

[Note 2:

Once the static data member has been defined, it exists even if no objects of its class have been created.

[Example 2:

In the example above, run_chain and running exist even if no objects of class process are created by the program.

— _end example_]

— _end note_]

The member shall still be defined in a namespace scope if it is odr-used ([basic.def.odr]) in the program and the namespace scope definition shall not contain an initializer.

The declaration of an inline static data member (which is a definition) may specify a brace-or-equal-initializer.

If the member is declared with the constexpr specifier, it may be redeclared in namespace scope with no initializer (this usage is deprecated; see [depr.static.constexpr]).

[Note 3:

There is exactly one definition of a static data member that is odr-used ([basic.def.odr]) in a valid program.

— _end note_]

[Note 4:

Static data members of a class in namespace scope have the linkage of the name of the class ([basic.link]).

— _end note_]

11.4.10 Bit-fields [class.bit]

A member-declarator of the form

specifies a bit-field.

A bit-field shall not be a static member.

A bit-field shall have integral or (possibly cv-qualified) enumeration type; the bit-field semantic property is not part of the type of the class member.

The constant-expression shall be an integral constant expression with a value greater than or equal to zero and is called the width of the bit-field.

If the width of a bit-field is larger than the width of the bit-field's type (or, in case of an enumeration type, of its underlying type), the extra bits are padding bits ([basic.types.general]).

Allocation of bit-fields within a class object isimplementation-defined.

Alignment of bit-fields is implementation-defined.

Bit-fields are packed into some addressable allocation unit.

[Note 1:

Bit-fields straddle allocation units on some machines and not on others.

Bit-fields are assigned right-to-left on some machines, left-to-right on others.

— _end note_]

A declaration for a bit-field that omits the identifierdeclares an unnamed bit-field.

Unnamed bit-fields are not members and cannot be initialized.

An unnamed bit-field shall not be declared with a cv-qualified type.

[Note 2:

An unnamed bit-field is useful for padding to conform to externally-imposed layouts.

— _end note_]

As a special case, an unnamed bit-field with a width of zero specifies alignment of the next bit-field at an allocation unit boundary.

Only when declaring an unnamed bit-field may the width be zero.

The address-of operator & shall not be applied to a bit-field, so there are no pointers to bit-fields.

A non-const reference shall not bind to a bit-field ([dcl.init.ref]).

[Note 3:

If the initializer for a reference of type const T& is an lvalue that refers to a bit-field, the reference is bound to a temporary initialized to hold the value of the bit-field; the reference is not bound to the bit-field directly.

— _end note_]

If a value of integral type (other than bool) is stored into a bit-field of width N and the value would be representable in a hypothetical signed or unsigned integer type with width N and the same signedness as the bit-field's type, the original value and the value of the bit-field compare equal.

If the value true or false is stored into a bit-field of type bool of any size (including a one bit bit-field), the original bool value and the value of the bit-field compare equal.

If a value of an enumeration type is stored into a bit-field of the same type and the width is large enough to hold all the values of that enumeration type ([dcl.enum]), the original value and the value of the bit-field compare equal.

[Example 1: enum BOOL { FALSE=0, TRUE=1 };struct A { BOOL b:1;}; A a;void f() { a.b = TRUE;if (a.b == TRUE) { } } — _end example_]

11.4.11 Allocation and deallocation functions [class.free]

Any allocation function for a classTis a static member (even if not explicitly declaredstatic).

[Example 1: class Arena;struct B { void* operator new(std::size_t, Arena*);};struct D1 : B { }; Arena* ap;void foo(int i) { new (ap) D1; new D1[i]; new D1; } — _end example_]

Any deallocation function for a classXis a static member (even if not explicitly declaredstatic).

[Example 2: 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*);}; — _end example_]

Since member allocation and deallocation functions arestaticthey cannot be virtual.

[Note 1:

However, when thecast-expressionof adelete-expressionrefers to an object of class type with a virtual destructor, because the deallocation function is chosen by the destructor of the dynamic type of the object, the effect is the same in that case.

[Example 3: struct B { virtual ~B();void operator delete(void*, std::size_t);};struct D : B { void operator delete(void*);};struct E : B { void log_deletion();void operator delete(E *p, std::destroying_delete_t) { p->log_deletion(); p->~E();::operator delete(p);} };void f() { B* bp = new D;delete bp; bp = new E;delete bp; }

Here, storage for the object of classDis deallocated byD​::​operator delete(), and the object of class E is destroyed and its storage is deallocated by E​::​operator delete(), due to the virtual destructor.

— _end example_]

— _end note_]

[Note 2:

Virtual destructors have no effect on the deallocation function actually called when thecast-expressionof adelete-expressionrefers to an array of objects of class type.

[Example 4: 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; B* bp = new D[i];delete[] bp; } — _end example_]

— _end note_]

Access to the deallocation function is checked statically, even if a different one is actually executed.

[Example 5:

For the call on line “// 1” above, ifB​::​operator delete()had been private, the delete expression would have been ill-formed.

— _end example_]

11.4.12 Nested class declarations [class.nest]

A class can be declared within another class.

A class declared within another is called a nested class.

[Note 1:

See [expr.prim.id] for restrictions on the use of non-static data members and non-static member functions.

— _end note_]

[Example 1: int x;int y;struct enclose { int x;static int s;struct inner { void f(int i) { int a = sizeof(x); x = i; s = i; ::x = i; y = i; } void g(enclose* p, int i) { p->x = i; } };}; inner* p = 0; — _end example_]

[Note 2:

Nested classes can be defined either in the enclosing class or in an enclosing namespace; member functions and static data members of a nested class can be defined either in the nested class or in an enclosing namespace scope.

[Example 2: 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; class I2;class I1 { }; };class E::I2 { }; — _end example_]

— _end note_]

A friend function ([class.friend]) defined within a nested class has no special access rights to members of an enclosing class.

11.5 Unions [class.union]

11.5.1 General [class.union.general]

A union is a class defined with the class-key union.

In a union, a non-static data member is activeif its name refers to an object whose lifetime has begun and has not ended ([basic.life]).

At most one of the non-static data members of an object of union type can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time.

[Note 1:

One special guarantee is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout structs that share a common initial sequence ([class.mem]), and if a non-static data member of an object of this standard-layout union type is active and is one of the standard-layout structs, the common initial sequence of any of the standard-layout struct members can be inspected; see [class.mem].

— _end note_]

The size of a union is sufficient to contain the largest of its non-static data members.

Each non-static data member is allocated as if it were the sole member of a non-union class.

[Note 2:

As a consequence, all non-static data members of a union object have the same address.

— _end note_]

A union can have member functions (including constructors and destructors),but it shall not have virtual ([class.virtual]) functions.

A union shall not have base classes.

A union shall not be used as a base class.

If a union contains a non-static data member of reference type, the program is ill-formed.

[Note 3:

If any non-static data member of a union has a non-trivial copy constructor, move constructor ([class.copy.ctor]), copy assignment operator, or move assignment operator ([class.copy.assign]), the corresponding member function of the union must be user-provided or it will be implicitly deleted ([dcl.fct.def.delete]) for the union.

[Example 1:

Consider the following union:union U { int i;float f; std::string s;};

Since std​::​string ([string.classes]) declares non-trivial versions of all of the special member functions, U will have an implicitly deleted copy/move constructor and copy/move assignment operator.

The default constructor and destructor of U are both trivial even though std​::​string has a non-trivial default constructor and a non-trivial destructor.

— _end example_]

— _end note_]

When the left operand of an assignment operator involves a member access expression ([expr.ref]) that nominates a union member, it may begin the lifetime of that union member, as described below.

For an expression E, define the set S(E)of subexpressions of Eas follows:

In an assignment expression of the form E1 = E2that uses either the built-in assignment operator ([expr.assign]) or a trivial assignment operator ([class.copy.assign]), for each element X of S(E1) and each anonymous union member X ([class.union.anon]) that is a member of a union and has such an element as an immediate subobject (recursively), if modification of X would have undefined behavior under [basic.life], an object of the type of X is implicitly created in the nominated storage; no initialization is performed and the beginning of its lifetime is sequenced after the value computation of the left and right operands and before the assignment.

[Note 4:

This ends the lifetime of the previously-active member of the union, if any ([basic.life]).

— _end note_]

[Example 2: union A { int x; int y[4]; };struct B { A a; };union C { B b; int k; };int f() { C c; c.b.a.y[3] = 4; return c.b.a.y[3]; } struct X { const int a; int b; };union Y { X x; int k; };void g() { Y y = { { 1, 2 } }; int n = y.x.a; y.k = 4; y.x.b = n; } — _end example_]

[Note 5:

In cases where the above rule does not apply, the active member of a union can only be changed by the use of a placement new-expression.

— _end note_]

[Example 3:

Consider an object u of a union type U having non-static data membersm of type M and n of type N.

If M has a non-trivial destructor and N has a non-trivial constructor (for instance, if they declare or inherit virtual functions), the active member of u can be safely switched from m ton using the destructor and placement new-expression as follows:u.m.~M();new (&u.n) N;

— _end example_]

11.5.2 Anonymous unions [class.union.anon]

A union of the form

union { member-specification } ;

is called an anonymous union; it defines an unnamed type and an unnamed object of that type called an anonymous union memberif it is a non-static data member or an anonymous union variable otherwise.

Each member-declaration in the member-specificationof an anonymous union shall either define one or more public non-static data members or be a static_assert-declaration.

Nested types, anonymous unions, and functions shall not be declared within an anonymous union.

The names of the members of an anonymous union are bound in the scope inhabited by the union declaration.

[Example 1: void f() { union { int a; const char* p; }; a = 1; p = "Jennifer";}

Here a and p are used like ordinary (non-member) variables, but since they are union members they have the same address.

— _end example_]

An anonymous union declared in the scope of a namespace with external linkage shall use the storage-class-specifier static.

Anonymous unions declared at block scope shall not use a storage-class-specifierthat is not permitted in the declaration of a block variable.

[Note 1:

A union for which objects, pointers, or references are declared is not an anonymous union.

[Example 2: void f() { union { int aa; char* p; } obj, *ptr = &obj; aa = 1; ptr->aa = 1; }

The assignment to plain aa is ill-formed since the member name is not visible outside the union, and even if it were visible, it is not associated with any particular object.

— _end example_]

— _end note_]

[Note 2:

Initialization of unions with no user-declared constructors is described in [dcl.init.aggr].

— _end note_]

A union-like class is a union or a class that has an anonymous union as a direct member.

A union-like class X has a set of variant members.

If X is a union, a non-static data member of X that is not an anonymous union is a variant member of X.

In addition, a non-static data member of an anonymous union that is a member of X is also a variant member of X.

At most one variant member of a union may have a default member initializer.

[Example 3: union U { int x = 0;union { int k;};union { int z;int y = 1; };}; — _end example_]

11.6 Local class declarations [class.local]

A class can be declared within a function definition; such a class is called a local class.

[Note 1:

A declaration in a local class cannot odr-use ([basic.def.odr]) a local entity from an enclosing scope.

— _end note_]

[Example 1: int x;void f() { static int s;int x;const int N = 5;extern int q();int arr[2];auto [y, z] = arr;struct local { int g() { return x; } int h() { return s; } int k() { return ::x; } int l() { return q(); } int m() { return N; } int* n() { return &N; } int p() { return y; } };}local* p = 0; — _end example_]

An enclosing function has no special access to members of the local class; it obeys the usual access rules ([class.access]).

Member functions of a local class shall be defined within their class definition, if they are defined at all.

A class nested within a local class is a local class.

A member of a local class X shall be declared only in the definition of X or, if the member is a nested class, in the nearest enclosing block scope of X.

[Note 2:

A local class cannot have static data members ([class.static.data]).

— _end note_]

11.7 Derived classes [class.derived]

11.7.1 General [class.derived.general]

A list of base classes can be specified in a class definition using the notation:

access-specifier:
private
protected
public

A class-or-decltype shall denote a (possibly cv-qualified) class type that is not an incompletely defined class ([class.mem]); any cv-qualifiers are ignored.

The class denoted by the class-or-decltype of a base-specifier is called adirect base classfor the class being defined.

A class B is a base class of a class D if it is a direct base class ofD or a direct base class of one of D's base classes.

A class is an indirect base class of another if it is a base class but not a direct base class.

A class is said to be (directly or indirectly) derived from its (direct or indirect) base classes.

[Note 1:

See [class.access] for the meaning ofaccess-specifier.

— _end note_]

Members of a base class are also members of the derived class.

[Note 2:

Constructors of a base class can be explicitly inherited ([namespace.udecl]).

Base class members can be referred to in expressions in the same manner as other members of the derived class, unless their names are hidden or ambiguous ([class.member.lookup]).

The scope resolution operator ​::​ ([expr.prim.id.qual]) can be used to refer to a direct or indirect base member explicitly, even if it is hidden in the derived class.

A derived class can itself serve as a base class subject to access control; see [class.access.base].

A pointer to a derived class can be implicitly converted to a pointer to an accessible unambiguous base class ([conv.ptr]).

An lvalue of a derived class type can be bound to a reference to an accessible unambiguous base class ([dcl.init.ref]).

— _end note_]

The base-specifier-list specifies the type of thebase class subobjects contained in an object of the derived class type.

[Example 1: struct Base { int a, b, c;};

struct Derived : Base { int b;};

struct Derived2 : Derived { int c;};

Here, an object of class Derived2 will have a subobject of classDerived which in turn will have a subobject of classBase.

— _end example_]

The order in which the base class subobjects are allocated in the most derived object ([intro.object]) is unspecified.

[Note 3:

A derived class and its base class subobjects can be represented by a directed acyclic graph (DAG) where an arrow means “directly derived from” (see Figure 3).

An arrow need not have a physical representation in memory.

A DAG of subobjects is often referred to as a “subobject lattice”.

— _end note_]

dag Base Base Derived1 Derived1 Derived1->Base Derived2 Derived2 Derived2->Derived1

Figure 3 — Directed acyclic graph [fig:class.dag]

[Note 4:

Initialization of objects representing base classes can be specified in constructors; see [class.base.init].

— _end note_]

[Note 5:

A base class subobject can have a layout different from the layout of a most derived object of the same type.

A base class subobject can have a polymorphic behavior ([class.cdtor]) different from the polymorphic behavior of a most derived object of the same type.

A base class subobject can be of zero size; however, two subobjects that have the same class type and that belong to the same most derived object cannot be allocated at the same address ([intro.object]).

— _end note_]

11.7.2 Multiple base classes [class.mi]

A class can be derived from any number of base classes.

[Note 1:

The use of more than one direct base class is often called multiple inheritance.

— _end note_]

[Example 1: class A { };class B { };class C { };class D : public A, public B, public C { }; — _end example_]

[Note 2:

The order of derivation is not significant except as specified by the semantics of initialization by constructor ([class.base.init]), cleanup ([class.dtor]), and storage layout ([class.mem], [class.access.spec]).

— _end note_]

A class shall not be specified as a direct base class of a derived class more than once.

[Note 3:

A class can be an indirect base class more than once and can be a direct and an indirect base class.

There are limited things that can be done with such a class; lookup that finds its non-static data members and member functions in the scope of the derived class will be ambiguous.

However, the static members, enumerations and types can be unambiguously referred to.

— _end note_]

[Example 2: class X { };class Y : public X, public X { }; class L { public: int next; };class A : public L { };class B : public L { };class C : public A, public B { void f(); }; class D : public A, public L { void f(); }; — _end example_]

A base class specifier that does not contain the keywordvirtual specifies a non-virtual base class.

A base class specifier that contains the keyword virtual specifies avirtual base class.

For each distinct occurrence of a non-virtual base class in the class lattice of the most derived class, the most derived object ([intro.object]) shall contain a corresponding distinct base class subobject of that type.

For each distinct base class that is specified virtual, the most derived object shall contain a single base class subobject of that type.

[Note 4:

For an object of class type C, each distinct occurrence of a (non-virtual) base class L in the class lattice of Ccorresponds one-to-one with a distinct L subobject within the object of type C.

Given the class C defined above, an object of class C will have two subobjects of class L as shown in Figure 4.

nonvirt L1 L L2 L A A A->L1 B B B->L2 C C C->A C->B

Figure 4 — Non-virtual base [fig:class.nonvirt]

In such lattices, explicit qualification can be used to specify which subobject is meant.

The body of function C​::​f can refer to the member next of each L subobject:void C::f() { A::next = B::next; }

Without the A​::​ or B​::​ qualifiers, the definition ofC​::​f above would be ill-formed because of ambiguity ([class.member.lookup]).

— _end note_]

[Note 5:

In contrast, consider the case with a virtual base class:class V { };class A : virtual public V { };class B : virtual public V { };class C : public A, public B { };

For an object c of class type C, a single subobject of type V is shared by every base class subobject of c that has avirtual base class of type V.

Given the class Cdefined above, an object of class C will have one subobject of class V, as shown in Figure 5.

— _end note_]

[Note 6:

A class can have both virtual and non-virtual base classes of a given type.

class B { };class X : virtual public B { };class Y : virtual public B { };class Z : public B { };class AA : public X, public Y, public Z { };

For an object of class AA, all virtual occurrences of base class B in the class lattice of AA correspond to a single B subobject within the object of type AA, and every other occurrence of a (non-virtual) base class B in the class lattice of AA corresponds one-to-one with a distinctB subobject within the object of type AA.

Given the class AA defined above, class AA has two subobjects of class B: Z's B and the virtual B shared by X and Y, as shown in Figure 6.

virtnonvirt B1 B B2 B AA AA X X AA->X Y Y AA->Y Z Z AA->Z X->B1 Y->B1 Z->B2

Figure 6 — Virtual and non-virtual base [fig:class.virtnonvirt]

— _end note_]

11.7.3 Virtual functions [class.virtual]

A non-static member function is a virtual functionif it is first declared with the keyword virtual or if it overrides a virtual member function declared in a base class (see below).92

[Note 1:

Virtual functions support dynamic binding and object-oriented programming.

— _end note_]

A class with a virtual member function is called a polymorphic class.93

If a virtual member function F is declared in a class B, and, in a class D derived (directly or indirectly) from B, a declaration of a member function Gcorresponds ([basic.scope.scope]) to a declaration of F, ignoring trailing requires-clauses, then G overrides94 F.

For convenience, we say that any virtual function overrides itself.

A virtual member function V of a class object S is a final overrider unless the most derived class ([intro.object]) of which S is a base class subobject (if any) has another member function that overrides V.

In a derived class, if a virtual member function of a base class subobject has more than one final overrider, the program is ill-formed.

[Example 1: 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(); c.C::f(); } — _end example_]

[Example 2: struct A { virtual void f(); };struct B : A { };struct C : A { void f(); };struct D : B, C { }; — _end example_]

[Note 2:

A virtual member function does not have to be visible to be overridden, for example,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.

However, f() declared in classD2 has the same name and the same parameter list asB​::​f(), and therefore is a virtual function that overrides the function B​::​f() even though B​::​f() is not visible in class D2.

— _end note_]

If a virtual function f in some class B is marked with thevirt-specifier final and in a class D derived from Ba function D​::​f overrides B​::​f, the program is ill-formed.

[Example 3: struct B { virtual void f() const final;};struct D : B { void f() const; }; — _end example_]

If a virtual function is marked with the virt-specifier override and does not override a member function of a base class, the program is ill-formed.

[Example 4: struct B { virtual void f(int);};struct D : B { virtual void f(long) override; virtual void f(int) override; }; — _end example_]

[Example 5: template<typename T> struct A { virtual void f() requires true; }; — _end example_]

The ref-qualifier, or lack thereof, of an overriding function shall be the same as that of the overridden function.

The return type of an overriding function shall be either identical to the return type of the overridden function or covariant with the classes of the functions.

If a function D​::​f overrides a function B​::​f, the return types of the functions are covariant if they satisfy the following criteria:

If the class type in the covariant return type of D​::​f differs from that ofB​::​f, the class type in the return type of D​::​f shall be complete at the locus ([basic.scope.pdecl]) of the overriding declaration or shall be the class type D.

When the overriding function is called as the final overrider of the overridden function, its result is converted to the type returned by the (statically chosen) overridden function ([expr.call]).

[Example 6: 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(); };class A;struct Derived : public Base { void vf1(); void vf2(int); char vf3(); D* vf4(); A* vf5(); void f();};void g() { Derived d; Base* bp = &d; bp->vf1(); bp->vf2(); bp->f(); B* p = bp->vf4(); Derived* dp = &d; D* q = dp->vf4(); dp->vf2(); } — _end example_]

[Note 3:

The interpretation of the call of a virtual function depends on the type of the object for which it is called (the dynamic type), whereas the interpretation of a call of a non-virtual member function depends only on the type of the pointer or reference denoting that object (the static type) ([expr.call]).

— _end note_]

[Note 4:

The virtual specifier implies membership, so a virtual function cannot be a non-member ([dcl.fct.spec]) function.

Nor can a virtual function be a static member, since a virtual function call relies on a specific object for determining which function to invoke.

A virtual function declared in one class can be declared a friend ([class.friend]) in another class.

— _end note_]

A virtual function declared in a class shall be defined, or declared pure ([class.abstract]) in that class, or both; no diagnostic is required ([basic.def.odr]).

[Example 7:

Here are some uses of virtual functions with multiple base classes:struct A { virtual void f();};struct B1 : A { void f();};struct B2 : A { void f();};struct D : B1, B2 { };void foo() { D d; B1* b1p = &d; A* ap = b1p; D* dp = &d; ap->f(); dp->f(); }

In class D above there are two occurrences of class Aand hence two occurrences of the virtual member function A​::​f.

The final overrider of B1​::​A​::​f is B1​::​f and the final overrider of B2​::​A​::​f is B2​::​f.

— _end example_]

[Example 8:

The following example shows a function that does not have a unique final overrider:struct A { virtual void f();};struct VB1 : virtual A { void f();};struct VB2 : virtual A { void f();};struct Error : VB1, VB2 { };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.

This example is therefore ill-formed.

Class Okay is well-formed, however, because Okay​::​f is a final overrider.

— _end example_]

[Example 9:

The following example uses the well-formed classes from above.

struct VB1a : virtual A { };struct Da : VB1a, VB2 { };void foe() { VB1a* vb1ap = new Da; vb1ap->f(); } — _end example_]

Explicit qualification with the scope operator ([expr.prim.id.qual]) suppresses the virtual call mechanism.

[Example 10: class B { public: virtual void f(); };class D : public B { public: void f(); };void D::f() { B::f(); }

Here, the function call inD​::​freally does callB​::​fand notD​::​f.

— _end example_]

A deleted function ([dcl.fct.def]) shall not override a function that is not deleted.

Likewise, a function that is not deleted shall not override a deleted function.

A consteval virtual function shall not override a virtual function that is not consteval.

A consteval virtual function shall not be overridden by a virtual function that is not consteval.

11.7.4 Abstract classes [class.abstract]

[Note 1:

The abstract class mechanism supports the notion of a general concept, such as a shape, of which only more concrete variants, such ascircle and square, can actually be used.

An abstract class can also be used to define an interface for which derived classes provide a variety of implementations.

— _end note_]

A virtual function is specified as a pure virtual function by using apure-specifier ([class.mem]) in the function declaration in the class definition.

[Note 2:

Such a function might be inherited: see below.

— _end note_]

A class is an abstract classif it has at least one pure virtual function.

[Note 3:

An abstract class can be used only as a base class of some other class; no objects of an abstract class can be created except as subobjects of a class derived from it ([basic.def], [class.mem]).

— _end note_]

[Example 1: class point { };class shape { point center;public: point where() { return center; } void move(point p) { center=p; draw(); } virtual void rotate(int) = 0; virtual void draw() = 0; }; — _end example_]

[Note 4:

A function declaration cannot provide both a pure-specifierand a definition.

— _end note_]

[Example 2: struct C { virtual void f() = 0 { }; }; — _end example_]

[Note 5:

An abstract class type cannot be used as a parameter or return type of a function being defined ([dcl.fct]) or called ([expr.call]), except as specified in [dcl.type.simple].

However, pointers and references to abstract class types can appear in such contexts.

— _end note_]

A class is abstract if it has at least one pure virtual function for which the final overrider is pure virtual.

[Example 3: class ab_circle : public shape { int radius;public: void rotate(int) { } };

Since shape​::​draw() is a pure virtual functionab_circle​::​draw() is a pure virtual by default.

The alternative declaration,class circle : public shape { int radius;public: void rotate(int) { } void draw(); };would make class circle non-abstract and a definition ofcircle​::​draw() must be provided.

— _end example_]

[Note 6:

An abstract class can be derived from a class that is not abstract, and a pure virtual function can override a virtual function which is not pure.

— _end note_]

Member functions can be called from a constructor (or destructor) of an abstract class;the effect of making a virtual call ([class.virtual]) to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined.

11.8 Member access control [class.access]

11.8.1 General [class.access.general]

A member of a class can be

[Note 1:

A constructor or destructor can be named by an expression ([basic.def.odr]) even though it has no name.

— _end note_]

A member of a class can also access all the members to which the class has access.

A local class of a member function may access the same members that the member function itself may access.96

Members of a class defined with the keywordclassare private by default.

Members of a class defined with the keywordsstruct or unionare public by default.

[Example 1: class X { int a; };struct S { int a; }; — _end example_]

Access control is applied uniformly to declarations and expressions.

When a using-declarator is named, access control is applied to it, not to the declarations that replace it.

For an overload set, access control is applied only to the function selected by overload resolution.

[Example 2: struct S { void f(int);private: void f(double);};void g(S* sp) { sp->f(2); } — _end example_]

[Note 3:

Because access control applies to the declarations named, if access control is applied to atypedef-name, only the accessibility of the typedef or alias declaration itself is considered.

The accessibility of the entity referred to by the typedef-name is not considered.

[Example 3: class A { class B { };public: typedef B BB;};void f() { A::BB x; A::B y; } — _end example_]

— _end note_]

[Note 4:

Access control does not prevent members from being found by name lookup or implicit conversions to base classes from being considered.

— _end note_]

The interpretation of a given construct is established without regard to access control.

If the interpretation established makes use of inaccessible members or base classes, the construct is ill-formed.

All access controls in [class.access] affect the ability to name a class member from the declaration of a particular entity, including parts of the declaration preceding the name of the entity being declared and, if the entity is a class, the definitions of members of the class appearing outside the class's member-specification.

[Note 5:

This access also applies to implicit references to constructors, conversion functions, and destructors.

— _end note_]

[Example 4: class A { typedef int I; I f() pre(A::x > 0);friend I g(I) post(A::x <= 0);static I x;template<int> struct Q;template<int> friend struct R;protected: struct B { };}; A::I A::f() pre(A::x > 0) { return 0; }A::I g(A::I p = A::x) post(A::x <= 0); 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 { };

Here, all the uses ofA​::​Iare well-formed becauseA​::​f,A​::​x, and A​::​Qare members of classAandgand R are friends of classA.

This implies, for example, that access checking on the first use ofA​::​Imust be deferred until it is determined that this use ofA​::​Iis as the return type of a member of classA.

Similarly, the use of A​::​B as abase-specifier is well-formed because Dis derived from A, so checking of base-specifier_s_must be deferred until the entire base-specifier-list has been seen.

— _end example_]

Access is checked for a default argument ([dcl.fct.default]) at the point of declaration, rather than at any points of use of the default argument.

Access checking for default arguments in function templates and in member functions of class templates is performed as described in [temp.inst].

Access for a default template-argument ([temp.param]) is checked in the context in which it appears rather than at any points of use of it.

[Example 5: 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; — _end example_]

11.8.2 Access specifiers [class.access.spec]

Member declarations can be labeled by anaccess-specifier ([class.derived]):

Anaccess-specifierspecifies the access rules for members following it until the end of the class or until anotheraccess-specifieris encountered.

[Example 1: class X { int a; public: int b; int c; }; — _end example_]

Any number of access specifiers is allowed and no particular order is required.

[Example 2: struct S { int a; protected: int b; private: int c; public: int d; }; — _end example_]

When a member is redeclared within its class definition, the access specified at its redeclaration shall be the same as at its initial declaration.

[Example 3: struct S { class A;enum E : int;private: class A { }; enum E: int { e0 }; }; — _end example_]

[Note 1:

In a derived class, the lookup of a base class name will find the injected-class-name instead of the name of the base class in the scope in which it was declared.

The injected-class-name might be less accessible than the name of the base class in the scope in which it was declared.

— _end note_]

[Example 4: class A { };class B : private A { };class C : public B { A* p; ::A* q; }; — _end example_]

11.8.3 Accessibility of base classes and base class members [class.access.base]

If a class is declared to be a base class ([class.derived]) for another class using thepublicaccess specifier, the public members of the base class are accessible as public members of the derived class and protected members of the base class are accessible as protected members of the derived class.

If a class is declared to be a base class for another class using theprotectedaccess specifier, the public and protected members of the base class are accessible as protected members of the derived class.

If a class is declared to be a base class for another class using theprivateaccess specifier, the public and protected members of the base class are accessible as private members of the derived class.97

In the absence of anaccess-specifierfor a base class,publicis assumed when the derived class is defined with the class-key structandprivateis assumed when the class is defined with the class-key class.

[Example 1: class B { };class D1 : private B { };class D2 : public B { };class D3 : B { }; struct D4 : public B { };struct D5 : private B { };struct D6 : B { }; class D7 : protected B { };struct D8 : protected B { };

HereBis a public base ofD2,D4, andD6, a private base ofD1,D3, andD5, and a protected base ofD7andD8.

— _end example_]

[Note 1:

A member of a private base class can be inaccessible as inherited, but accessible directly.

Because of the rules on pointer conversions ([conv.ptr]) and explicit casts ([expr.type.conv], [expr.static.cast], [expr.cast]), a conversion from a pointer to a derived class to a pointer to an inaccessible base class can be ill-formed if an implicit conversion is used, but well-formed if an explicit cast is used.

[Example 2: class B { public: int mi; static int si; };class D : private B { };class DD : public D { void f();};void DD::f() { mi = 3; si = 3; ::B b; b.mi = 3; b.si = 3; ::B::si = 3; ::B* bp1 = this; ::B* bp2 = (::B*)this; bp2->mi = 3; } — _end example_]

— _end note_]

A base classBofNisaccessibleat_R_, if

[Example 3: class B { public: int m;};class S: private B { friend class N;};class N: private S { void f() { B* p = this; } }; — _end example_]

If a base class is accessible, one can implicitly convert a pointer to a derived class to a pointer to that base class ([conv.ptr], [conv.mem]).

[Note 2:

It follows that members and friends of a classXcan implicitly convert anX*to a pointer to a private or protected immediate base class ofX.

— _end note_]

The access to a member is affected by the class in which the member is named.

This naming class is the class in whose scope name lookup performed a search that found the member.

[Note 3:

This class can be explicit, e.g., when aqualified-idis used, or implicit, e.g., when a class member access operator ([expr.ref]) is used (including cases where an implicit “this->” is added).

If both a class member access operator and aqualified-idare used to name the member (as inp->T​::​m), the class naming the member is the class denoted by thenested-name-specifierof thequalified-id(that is,T).

— _end note_]

A membermis accessible at the point_R_when named in classNif

If a class member access operator, including an implicit “this->”, is used to access a non-static data member or non-static member function, the reference is ill-formed if the left operand (considered as a pointer in the “.” operator case) cannot be implicitly converted to a pointer to the naming class of the right operand.

[Note 4:

This requirement is in addition to the requirement that the member be accessible as named.

— _end note_]

11.8.4 Friends [class.friend]

A friend of a class is a function or class that is given permission to name the private and protected members of the class.

A class specifies its friends, if any, by way of friend declarations.

Such declarations give special access rights to the friends, but they do not make the nominated friends members of the befriending class.

[Example 1:

The following example illustrates the differences between members and friends: 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);}

— _end example_]

Declaring a class to be a friend implies that private and protected members of the class granting friendship can be named in thebase-specifiers and member declarations of the befriended class.

[Example 2: class A { class B { };friend class X;};struct X : A::B { A::B mx; class Y { A::B my; };}; — _end example_]

[Example 3: class X { enum { a=100 };friend class Y;};class Y { int v[X::a]; };class Z { int v[X::a]; }; — _end example_]

A friend declaration that does not declare a function shall be a friend-type-declaration.

If a friend-type-specifier in a friend declaration designates a (possibly cv-qualified) class type, that class is declared as a friend; otherwise, thefriend-type-specifier is ignored.

[Example 4: class C;typedef C Ct;class E;class X1 { friend C; };class X2 { friend Ct; friend D; friend class D; };template <typename ... Ts> class R { friend Ts...;};template <class... Ts, class... Us> class R<R<Ts...>, R<Us...>> { friend Ts::Nested..., Us...;}; R<C> rc; R<C, E> rce; R<int> Ri; struct E { struct Nested; }; R<R<E>, R<C, int>> rr; — _end example_]

[Note 2:

A friend declaration refers to an entity, not (all overloads of) a name.

A member function of a classXcan be a friend of a classY.

[Example 5: class Y { friend char* X::foo(int);friend X::X(char); friend X::~X(); }; — _end example_]

— _end note_]

A function may be defined in a friend declaration of a class if and only if the class is a non-local class ([class.local]) and the function name is unqualified.

[Example 6: class M { friend void f() { } }; — _end example_]

Such a function is implicitly an inline ([dcl.inline]) function if it is attached to the global module.

[Note 3:

If a friend function is defined outside a class, it is not in the scope of the class.

— _end note_]

A member nominated by a friend declaration shall be accessible in the class containing the friend declaration.

The meaning of the friend declaration is the same whether the friend declaration appears in the private, protected, or public ([class.mem]) portion of the classmember-specification.

Friendship is neither inherited nor transitive.

[Example 7: class A { friend class B;int a;};class B { friend class C;};class C { void f(A* p) { p->a++; } };class D : public B { void f(A* p) { p->a++; } }; — _end example_]

[Example 8: void h(int);template <class T> void f2(T);namespace A { class X { friend void f(X); class Y { friend void g(); friend void h(int); friend void f2<>(int); };}; X x;void g() { f(x); } void f(X) { } void h(int) { } } using A::x;void h() { A::f(x); A::X::f(x); A::X::Y::g(); } — _end example_]

[Example 9: class X;void a();void f() { class Y;extern void b();class A { friend class X; friend class Y; friend class Z; friend void a(); friend void b(); friend void c(); }; X* px; Z* pz; } — _end example_]

11.8.5 Protected member access [class.protected]

An additional access check beyond those described earlier in [class.access]is applied when a non-static data member or non-static member function is a protected member of its naming class ([class.access.base]).98

As described earlier, access to a protected member is granted because the reference occurs in a friend or direct member of some class C.

All other accesses involve a (possibly implicit) object expression ([expr.ref]).

In this case, the class of the object expression shall beC or a class derived from C.

[Example 1: 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; p1->i = 2; p2->i = 3; p2->B::i = 4; int B::* pmi_B = &B::i; int B::* pmi_B2 = &D2::i; B::j = 5; D2::j = 6; } void D2::mem(B* pb, D1* p1) { pb->i = 1; p1->i = 2; i = 3; B::i = 4; int B::* pmi_B = &B::i; int B::* pmi_B2 = &D2::i; j = 5; B::j = 6; } void g(B* pb, D1* p1, D2* p2) { pb->i = 1; p1->i = 2; p2->i = 3; } — _end example_]

11.8.6 Access to virtual functions [class.access.virt]

The access rules ([class.access]) for a virtual function are determined by its declaration and are not affected by the rules for a function that later overrides it.

[Example 1: 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(); pd->f(); } — _end example_]

Access is checked at the call point using the type of the expression used to denote the object for which the member function is called (B*in the example above).

The access of the member function in the class in which it was defined (Din the example above) is in general not known.

11.8.7 Multiple access [class.paths]

If a declaration can be reached by several paths through a multiple inheritance graph, the access is that of the path that gives most access.

[Example 1: class W { public: void f(); };class A : private virtual W { };class B : public virtual W { };class C : public A, public B { void f() { W::f(); } };

SinceW​::​f()is available toC​::​f()along the public path throughB, access is allowed.

— _end example_]

11.8.8 Nested classes [class.access.nest]

A nested class is a member and as such has the same access rights as any other member.

The members of an enclosing class have no special access to members of a nested class; the usual access rules ([class.access]) shall be obeyed.

[Example 1: class E { int x;class B { };class I { B b; int y;void f(E* p, int i) { p->x = i; } };int g(I* p) { return p->y; } }; — _end example_]

11.9 Initialization [class.init]

11.9.1 General [class.init.general]

When no initializer is specified for an object of (possibly cv-qualified) class type (or array thereof), or the initializer has the form(), the object is initialized as specified in [dcl.init].

An object of class type (or array thereof) can be explicitly initialized; see [class.expl.init] and [class.base.init].

When an array of class objects is initialized (either explicitly or implicitly) and the elements are initialized by constructor, the constructor shall be called for each element of the array, following the subscript order; see [dcl.array].

[Note 1:

Destructors for the array elements are called in reverse order of their construction.

— _end note_]

11.9.2 Explicit initialization [class.expl.init]

An object of class type can be initialized with a parenthesizedexpression-list, where theexpression-listis construed as an argument list for a constructor that is called to initialize the object.

Either direct-initialization semantics or copy-initialization semantics apply; see [dcl.init].

[Example 1: struct complex { complex(); complex(double); complex(double,double);}; complex sqrt(complex,complex); complex a(1); complex b = a; complex c = complex(1,2); complex d = sqrt(b,c); complex e; complex f = 3; complex g = { 1, 2 }; — _end example_]

[Note 1:

Overloading of the assignment operator ([over.assign]) has no effect on initialization.

— _end note_]

An object of class type can also be initialized by abraced-init-list.

[Example 2: complex v[6] = { 1, complex(1,2), complex(), 2 };

Here,complex​::​complex(double)is called for the initialization ofv[0]andv[3],complex​::​complex(​double, double)is called for the initialization ofv[1],complex​::​complex()is called for the initialization ofv[2],v[4], andv[5].

For another example,

struct X { int i;float f; complex c;} x = { 99, 88.8, 77.7 };

Here,x.iis initialized with 99,x.fis initialized with 88.8, andcomplex​::​complex(double)is called for the initialization ofx.c.

— _end example_]

[Note 2:

Braces can be elided in theinitializer-listfor any aggregate, even if the aggregate has members of a class type with user-defined type conversions; see [dcl.init.aggr].

— _end note_]

[Note 3:

IfTis a class type with no default constructor, any initializing declaration of an object of typeT(or array thereof) is ill-formed if noinitializeris explicitly specified (see [class.init] and [dcl.init]).

— _end note_]

11.9.3 Initializing bases and members [class.base.init]

In the definition of a constructor for a class, initializers for direct and virtual base class subobjects and non-static data members can be specified by actor-initializer, which has the form

Lookup for an unqualified name in a mem-initializer-idignores the constructor's function parameter scope.

[Note 1:

If the constructor's class contains a member with the same name as a direct or virtual base class of the class, amem-initializer-idnaming the member or base class and composed of a single identifier refers to the class member.

Amem-initializer-idfor the hidden base class can be specified using a qualified name.

— _end note_]

Unless themem-initializer-idnames the constructor's class, a non-static data member of the constructor's class, or a direct or virtual base of that class, themem-initializeris ill-formed.

Amem-initializer-listcan initialize a base class using any class-or-decltype that denotes that base class type.

[Example 1: struct A { A(); };typedef A global_A;struct B { };struct C: public A, public B { C(); }; C::C(): global_A() { } — _end example_]

If amem-initializer-idis ambiguous because it designates both a direct non-virtual base class and an indirect virtual base class, themem-initializeris ill-formed.

[Example 2: struct A { A(); };struct B: public virtual A { };struct C: public A, public B { C(); }; C::C(): A() { } — _end example_]

Actor-initializermay initialize a variant member of the constructor's class.

If actor-initializerspecifies more than onemem-initializerfor the same member or for the same base class, thector-initializeris ill-formed.

A mem-initializer-list can delegate to another constructor of the constructor's class using anyclass-or-decltype that denotes the constructor's class itself.

If amem-initializer-id designates the constructor's class, it shall be the only mem-initializer; the constructor is a delegating constructor, and the constructor selected by themem-initializer is the target constructor.

The target constructor is selected by overload resolution.

Once the target constructor returns, the body of the delegating constructor is executed.

If a constructor delegates to itself directly or indirectly, the program is ill-formed, no diagnostic required.

[Example 3: struct C { C( int ) { } C(): C(42) { } C( char c ) : C(42.0) { } C( double d ) : C('a') { } }; — _end example_]

Theexpression-listor braced-init-listin amem-initializeris used to initialize the designated subobject (or, in the case of a delegating constructor, the complete class object) according to the initialization rules of [dcl.init] for direct-initialization.

[Example 4: 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); — _end example_]

[Note 2:

The initialization performed by each mem-initializerconstitutes a full-expression ([intro.execution]).

Any expression in amem-initializeris evaluated as part of the full-expression that performs the initialization.

— _end note_]

A mem-initializer where the mem-initializer-id denotes a virtual base class is ignored during execution of a constructor of any class that is not the most derived class.

A temporary expression bound to a reference member in a mem-initializeris ill-formed.

[Example 5: struct A { A() : v(42) { } const int& v;}; — _end example_]

In a non-delegating constructor other than an implicitly-defined copy/move constructor ([class.copy.ctor]), if a given potentially constructed subobject is not designated by amem-initializer-id(including the case where there is nomem-initializer-listbecause the constructor has noctor-initializer), then

[Note 3:

An abstract class ([class.abstract]) is never a most derived class, thus its constructors never initialize virtual base classes, therefore the corresponding mem-initializers can be omitted.

— _end note_]

An attempt to initialize more than one non-static data member of a union renders the program ill-formed.

[Note 4:

After the call to a constructor for classXfor an object with automatic or dynamic storage duration has completed, if the constructor was not invoked as part of value-initialization and a member ofXis neither initialized nor given a value during execution of the compound-statement of the body of the constructor, the member has an indeterminate or erroneous value ([basic.indet]).

— _end note_]

[Example 6: struct A { A();};struct B { B(int);};struct C { C() { } A a; const B b; int i; int j = 5; }; — _end example_]

If a given non-static data member has both a default member initializer and a mem-initializer, the initialization specified by themem-initializer is performed, and the non-static data member's default member initializer is ignored.

[Example 7:

Givenstruct A { int i = ; A(int arg) : i(arg) { } };the A(int) constructor will simply initialize i to the value ofarg, and theside effects in i's default member initializer will not take place.

— _end example_]

A temporary expression bound to a reference member from a default member initializer is ill-formed.

[Example 8: struct A { A() = default; A(int v) : v(v) { } const int& v = 42; }; A a1; A a2(1); — _end example_]

In a non-delegating constructor, the destructor for each potentially constructed subobject of class type is potentially invoked ([class.dtor]).

[Note 5:

This provision ensures that destructors can be called for fully-constructed subobjects in case an exception is thrown ([except.ctor]).

— _end note_]

In a non-delegating constructor, initialization proceeds in the following order:

[Note 6:

The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization.

— _end note_]

[Example 9: 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); A a(2); B b(3); C c(4); — _end example_]

[Note 7:

The expression-list or braced-init-listof a mem-initializeris in the function parameter scope of the constructor and can use this to refer to the object being initialized.

— _end note_]

[Example 10: 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) { } };

initializesX​::​rto refer toX​::​a, initializesX​::​bwith the value of the constructor parameteri, initializesX​::​iwith the value of the constructor parameteri, and initializesX​::​jwith the value ofX​::​i; this takes place each time an object of classXis created.

— _end example_]

Member functions (including virtual member functions, [class.virtual]) can be called for an object under construction or destruction.

Similarly, an object under construction or destruction can be the operand of thetypeidoperator ([expr.typeid]) or of adynamic_cast ([expr.dynamic.cast]).

However, if these operations are performed during evaluation of

the program has undefined behavior.

[Example 11: class A { public: A(int);};class B : public A { int j;public: int f(); B() : A(f()), j(f()) { } };class C { public: C(int);};class D : public B, C { int i;public: D() : C(f()), i(f()) { } }; — _end example_]

[Note 8:

[class.cdtor] describes the results of virtual function calls,typeidanddynamic_casts during construction for the well-defined cases; that is, describes the polymorphic behavior of an object under construction.

— _end note_]

A mem-initializer followed by an ellipsis is a pack expansion ([temp.variadic]) that initializes the base classes specified by a pack expansion in the base-specifier-listfor the class.

[Example 12: template<class... Mixins> class X : public Mixins... { public: X(const Mixins&... mixins) : Mixins(mixins)... { } }; — _end example_]

11.9.4 Initialization by inherited constructor [class.inhctor.init]

When a constructor for type B is invoked to initialize an object of a different type D(that is, when the constructor was inherited ([namespace.udecl])), initialization proceeds as if a defaulted default constructor were used to initialize the D object and each base class subobject from which the constructor was inherited, except that the B subobject is initialized by the inherited constructor if the base class subobject were to be initialized as part of the D object ([class.base.init]).

The invocation of the inherited constructor, including the evaluation of any arguments, is omitted if the B subobject is not to be initialized as part of the D object.

The complete initialization is considered to be a single function call; in particular, unless omitted, the initialization of the inherited constructor's parameters is sequenced before the initialization of any part of the D object.

[Example 1: struct B1 { B1(int, ...) { } };struct B2 { B2(double) { } };int get();struct D1 : B1 { using B1::B1; int x;int y = get();};void test() { D1 d(2, 3, 4); D1 e; } struct D2 : B2 { using B2::B2; B1 b;}; D2 f(1.0); 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); template<class T> struct Log : T { using T::T; ~Log() { std::clog << "Destroying wrapper" << std::endl; } };

Class template Log wraps any class and forwards all of its constructors, while writing a message to the standard log whenever an object of class Log is destroyed.

— _end example_]

[Example 2: struct V { V() = default; V(int); };struct Q { Q(); };struct A : virtual V, Q { using V::V; A() = delete;};int bar() { return 42; } struct B : A { B() : A(bar()) {} };struct C : B {};void foo() { C c; } — _end example_]

If the constructor was inherited from multiple base class subobjects of type B, the program is ill-formed.

[Example 3: 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); D2 d2(0); 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); — _end example_]

When an object is initialized by an inherited constructor, initialization of the object is complete when the initialization of all subobjects is complete.

11.9.5 Construction and destruction [class.cdtor]

For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior.

For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor finishes execution results in undefined behavior.

[Example 1: struct X { int i; };struct Y : X { Y(); }; struct A { int a; };struct B : public A { int j; Y y; }; extern B bobj; B* pb = &bobj; int* p1 = &bobj.a; int* p2 = &bobj.y.i; A* pa = &bobj; B bobj; extern X xobj;int* p3 = &xobj.i; X xobj;

For another example,struct W { int j; };struct X : public virtual W { };struct Y { int* p; X x; Y() : p(&x.j) { } };

— _end example_]

During the construction of an object, if the value of any of its subobjects or any element of its object representation is accessed through a glvalue that is not obtained, directly or indirectly, from the constructor'sthispointer, the value thus obtained is unspecified.

[Example 2: 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; cptr->c = 1; cout << cobj.c * 100 << '\n';} extern struct D d;struct D { D(int a) : a(a), b(d.a) {} int a, b;}; D d = D(1); — _end example_]

To explicitly or implicitly convert a pointer (a glvalue) referring to an object of classXto a pointer (reference) to a direct or indirect base classBofX, the construction ofXand the construction of all of its direct or indirect bases that directly or indirectly derive fromBshall have started and the destruction of these classes shall not have completed, otherwise the conversion results in undefined behavior.

To form a pointer to (or access the value of) a direct non-static member of an objectobj, the construction ofobjshall have started and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing the member value) results in undefined behavior.

[Example 3: 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), X(this) {} }; — _end example_]

Member functions, including virtual functions ([class.virtual]), can be called during construction or destruction ([class.base.init]).

When a virtual function is called directly or indirectly from a constructor or from a destructor, including during the construction or destruction of the class's non-static data members, or during the evaluation of a postcondition assertion of a constructor or a precondition assertion of a destructor ([dcl.contract.func]), and the object to which the call applies is the object (call it x) under construction or destruction, the function called is the final overrider in the constructor's or destructor's class and not one overriding it in a more-derived class.

If the virtual function call uses an explicit class member access ([expr.ref]) and the object expression refers to the complete object of x or one of that object's base class subobjects but not x or one of its base class subobjects, the behavior is undefined.

[Example 4: 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(); g(); v->g(); a->f(); } — _end example_]

Thetypeidoperator ([expr.typeid]) can be used during construction or destruction ([class.base.init]).

Whentypeidis used in a constructor (including themem-initializer or default member initializer ([class.mem]) for a non-static data member) or in a destructor, or used in a function called (directly or indirectly) from a constructor or destructor, if the operand oftypeidrefers to the object under construction or destruction,typeidyields thestd​::​type_infoobject representing the constructor or destructor's class.

If the operand oftypeidrefers to the object under construction or destruction and the static type of the operand is neither the constructor or destructor's class nor one of its bases, the behavior is undefined.

dynamic_casts ([expr.dynamic.cast]) can be used during construction or destruction ([class.base.init]).

When adynamic_castis used in a constructor (including themem-initializer or default member initializer for a non-static data member) or in a destructor, or used in a function called (directly or indirectly) from a constructor or destructor, if the operand of thedynamic_castrefers to the object under construction or destruction, this object is considered to be a most derived object that has the type of the constructor or destructor's class.

If the operand of thedynamic_castrefers to the object under construction or destruction and the static type of the operand is not a pointer to or object of the constructor or destructor's own class or one of its bases, thedynamic_castresults in undefined behavior.

[Example 5: 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); typeid(*v); typeid(*a); dynamic_cast<B*>(v); dynamic_cast<B*>(a); } — _end example_]

11.9.6 Copy/move elision [class.copy.elision]

When certain criteria are met, an implementation is allowed to omit the creation of a class object from a source object of the same type (ignoring cv-qualification), even if the selected constructor and/or the destructor for the object haveside effects.

In such cases, the implementation treats the source and target of the omitted initialization as simply two different ways of referring to the same object.

If the first parameter of the selected constructor is an rvalue reference to the object's type, the destruction of that object occurs when the target would have been destroyed; otherwise, the destruction occurs at the later of the times when the two objects would have been destroyed without the optimization.

[Note 1:

Because only one object is destroyed instead of two, and the creation of one object is omitted, there is still one object destroyed for each one constructed.

— _end note_]

This elision of object creation, calledcopy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

Copy elision is not permitted where an expression is evaluated in a context requiring a constant expression ([expr.const]) and in constant initialization ([basic.start.static]).

[Note 3:

It is possible that copy elision is performed if the same expression is evaluated in another context.

— _end note_]

[Example 1: 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 loc;return loc;} constexpr A a; constexpr A b = g(); void h() { A c = g(); }

Here the criteria for elision can eliminate the copying of the object t with automatic storage duration into the result object for the function call f(), which is the non-local object t2.

Effectively, the construction of tcan be viewed as directly initializing t2, and that object's destruction will occur at program exit.

Adding a move constructor to Thing has the same effect, but it is the move construction from the object with automatic storage duration to t2 that is elided.

— _end example_]

[Example 2: class Thing { public: Thing();~Thing(); Thing(Thing&&);private: Thing(const Thing&);}; Thing f(bool b) { Thing t;if (b) throw t; return t; }Thing t2 = f(false); struct Weird { Weird(); Weird(Weird&);}; Weird g(bool b) { static Weird w1; Weird w2;if (b) return w1; else return w2; } int& h(bool b, int i) { static int s;if (b) return s; else return i; } decltype(auto) h2(Thing t) { return t; } decltype(auto) h3(Thing t) { return (t); } — _end example_]

[Example 3: template<class T> void g(const T&);template<class T> void f() { T x;try { T y;try { g(x); } catch (...) { if () throw x; throw y; } g(y);} catch(...) { g(x); g(y); } } — _end example_]

11.10 Comparisons [class.compare]

11.10.1 Defaulted comparison operator functions [class.compare.default]

A defaulted comparison operator function ([over.binary]) shall be a non-template function that

Such a comparison operator function is termeda defaulted comparison operator function for class C.

Name lookups and access checks in the implicit definition ([dcl.fct.def.default]) of a comparison operator function are performed from a context equivalent to its function-body.

A definition of a comparison operator as defaulted that appears in a class shall be the first declaration of that function.

[Example 1: struct S;bool operator==(S, S) = default; struct S { friend bool operator==(S, const S&) = default; };enum E { };bool operator==(E, E) = default; — _end example_]

A defaulted <=> or == operator function for class C is defined as deleted if any non-static data member of C is of reference type orC has variant members ([class.union.anon]).

A binary operator expression a @ b isusableif either

If the member-specificationdoes not explicitly declare any member or friend named operator==, an == operator function is declared implicitly for each three-way comparison operator function defined as defaulted in the member-specification, with the same access and function-definition and in the same class scope as the respective three-way comparison operator function, except that the return type is replaced with bool and the declarator-id is replaced with operator==.

[Note 1:

Such an implicitly-declared == operator for a class Xis defined as defaulted in the definition of X and has the same parameter-declaration-clause and trailing requires-clause as the respective three-way comparison operator.

It is declared with friend, virtual, constexpr, or consteval if the three-way comparison operator function is so declared.

If the three-way comparison operator function has no noexcept-specifier, the implicitly-declared == operator function has an implicit exception specification ([except.spec]) that can differ from the implicit exception specification of the three-way comparison operator function.

— _end note_]

[Example 2: template<typename T> struct X { friend constexpr std::partial_ordering operator<=>(X, X) requires (sizeof(T) != 1) = default;[[nodiscard]] virtual std::strong_ordering operator<=>(const X&) const = default;}; — _end example_]

[Note 2:

The == operator function is declared implicitly even if the defaulted three-way comparison operator function is defined as deleted.

— _end note_]

The direct base class subobjects of C, in the order of their declaration in the base-specifier-list of C, followed by the non-static data members of C, in the order of their declaration in the member-specification of C, form a list of subobjects.

In that list, any subobject of array type is recursively expanded to the sequence of its elements, in the order of increasing subscript.

Let be an lvalue denoting the element in the expanded list of subobjects for an object x(of length n), where is formed by a sequence of derived-to-base conversions ([over.best.ics]), class member access expressions ([expr.ref]), and array subscript expressions ([expr.sub]) applied to x.

11.10.2 Equality operator [class.eq]

A defaulted equality operator function ([over.binary]) shall have a declared return type bool.

A defaulted == operator function for a class Cis defined as deleted unless, for each in the expanded list of subobjects for an object x of type C,is usable ([class.compare.default]).

The return value of a defaulted == operator function with parameters x and y is determined by comparing corresponding elements and in the expanded lists of subobjects for x and y(in increasing index order) until the first index iwhere yields a result value which, when contextually converted to bool, yields false.

The return value is false if such an index exists and true otherwise.

[Example 1: struct D { int i;friend bool operator==(const D& x, const D& y) = default;}; — _end example_]

11.10.3 Three-way comparison [class.spaceship]

The synthesized three-way comparisonof type R ([cmp.categories]) of glvalues a and b of the same type is defined as follows:

[Note 1:

A synthesized three-way comparison is ill-formed if overload resolution finds usable candidates that do not otherwise meet the requirements implied by the defined expression.

— _end note_]

Let R be the declared return type of a defaulted three-way comparison operator function, and let be the elements of the expanded list of subobjects for an object x of type C.

The return value of type Rof the defaulted three-way comparison operator function with parameters x and y of the same type is determined by comparing corresponding elements and in the expanded lists of subobjects for x and y(in increasing index order) until the first index i where the synthesized three-way comparison of type Rbetween and yields a result value where , contextually converted to bool, yields true.

The return value is a copy of if such an index exists andstatic_cast<R>(std​::​strong_ordering​::​equal) otherwise.

The common comparison type Uof a possibly-empty list of n comparison category types, , …, is defined as follows:

11.10.4 Secondary comparison operators [class.compare.secondary]

A secondary comparison operator is a relational operator ([expr.rel]) or the != operator.

A defaulted operator function ([over.binary]) for a secondary comparison operator @shall have a declared return type bool.

The operator function with parameters x and yis defined as deleted if

In any of the two overload resolutions above, the defaulted operator function is not considered as a candidate for the @ operator.

Otherwise, the operator function yields x @ y.

[Example 1: struct HasNoLessThan { };struct C { friend HasNoLessThan operator<=>(const C&, const C&);bool operator<(const C&) const = default; }; — _end example_]