Files
2025-10-25 03:02:53 +03:00

34 KiB
Raw Permalink Blame History

[class.mem.general]

11 Classes [class]

11.4 Class members [class.mem]

11.4.1 General [class.mem.general]

member-specification:
member-declaration member-specificationopt
access-specifier : member-specificationopt

member-declaration:
attribute-specifier-seqopt decl-specifier-seqopt member-declarator-listopt ;
function-definition
friend-type-declaration
using-declaration
using-enum-declaration
static_assert-declaration
consteval-block-declaration
template-declaration
explicit-specialization
deduction-guide
alias-declaration
opaque-enum-declaration
empty-declaration

member-declarator-list:
member-declarator
member-declarator-list , member-declarator

member-declarator:
declarator virt-specifier-seqopt function-contract-specifier-seqopt pure-specifieropt
declarator requires-clause function-contract-specifier-seqopt
declarator brace-or-equal-initializer
identifieropt attribute-specifier-seqopt : constant-expression brace-or-equal-initializeropt

virt-specifier-seq:
virt-specifier virt-specifier-seqopt

virt-specifier:
override
final

pure-specifier:
= 0

friend-type-declaration:
friend friend-type-specifier-list ;

friend-type-specifier-list:
friend-type-specifier ...opt
friend-type-specifier-list , friend-type-specifier ...opt

friend-type-specifier:
simple-type-specifier
elaborated-type-specifier
typename-specifier

1

#

In the absence of a virt-specifier-seq, the token sequence = 0 is treated as a pure-specifier if the type of the declarator-id ([dcl.meaning.general]) is a function type, and is otherwise treated as a brace-or-equal-initializer.

[Note 1:

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

— end note]

2

#

The optional function-contract-specifier-seq ([dcl.contract.func]) in a member-declarator shall be present only if the declarator declares a function.

3

#

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 X that 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]

4

#

A member-declaration does not itself declare new members of the class if it is

a friend declaration ([class.friend]),

a deduction-guide ([temp.deduct.guide]),

a template-declaration whose declaration is one of the above,

a static_assert-declaration,

a consteval-block-declaration,

a using-declaration ([namespace.udecl]), or

an empty-declaration.

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

5

#

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.

6

#

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).

7

#

Every object of class type has a unique member subobject corresponding to each of its direct non-static data members.

If any non-static data member of a class C is of reference type, then let D be an invented class that is identical to C except that each non-static member of D corresponding to a member of C of type “reference to T” instead has type “pointer to T”.

Every member subobject of a complete object of type C has the same size, alignment, and offset as that of the corresponding subobject of a complete object of type D.

The size and alignment of C are the same as the size and alignment of D.

8

#

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

a nested class or member class template can be declared and then later defined, and

an enumeration can be introduced with an opaque-enum-declaration and later redeclared with an enum-specifier.

[Note 3:

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

— end note]

9

#

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.

10

#

A complete-class context of a class (template) is a

function body ([dcl.fct.def.general]),

default argument ([dcl.fct.default]),

default template argument ([temp.param]),

noexcept-specifier ([except.spec]),

function-contract-specifier ([dcl.contract.func]), or

default member initializer

within the member-specification of the class or class template.

[Note 4:

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]

11

#

A class C is complete at a program point P if 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.

12

#

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

13

#

In a member-declarator, an = immediately following the declarator is interpreted as introducing a pure-specifier if the declarator-id has function type, otherwise it is interpreted as introducing a brace-or-equal-initializer.

[Example 1: struct S {using T = void(); T * p = 0; // OK, brace-or-equal-initializervirtual T f = 0; // OK, pure-specifier}; — end example]

14

#

In a member-declarator for a bit-field, the constant-expression is parsed as the longest sequence of tokens that could syntactically form a constant-expression.

[Example 2: int a;const int b = 0;struct S {int x1 : 8 = 42; // OK, "= 42" is brace-or-equal-initializerint x2 : 8 { 42 }; // OK, "{ 42 }" is brace-or-equal-initializerint y1 : true ? 8 : a = 42; // OK, brace-or-equal-initializer is absentint y2 : true ? 8 : b = 42; // error: cannot assign to const intint y3 : (true ? 8 : b) = 42; // OK, "= 42" is brace-or-equal-initializerint z : 1 || new int { 0 }; // OK, brace-or-equal-initializer is absent}; — end example]

15

#

A brace-or-equal-initializer shall appear only in the declaration of a data member.

(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.

16

#

A member shall not be declared with the externstorage-class-specifier.

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

17

#

The decl-specifier-seq may be omitted in constructor, destructor, and conversion function declarations only; when declaring another kind of member the decl-specifier-seq shall contain a type-specifier that is not a cv-qualifier.

Themember-declarator-list can be omitted only after aclass-specifier or an enum-specifier or in afriend declaration.

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

18

#

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

19

#

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

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

20

#

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 5:

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]

21

#

[Note 6:

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

— end note]

22

#

[Note 7:

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]

23

#

[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]

24

#

[Note 8:

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]

25

#

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

every static data member of class T;

every member function of class T; [Note 9: This restriction does not apply to constructors, which do not have names ([class.ctor]). — end note]

every member of class T that is itself a type;

every member template of class T;

every enumerator of every member of class T that is an unscoped enumeration type; and

every member of every anonymous union that is a member of classT.

26

#

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

27

#

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

corresponding entities have layout-compatible types ([basic.types]),

corresponding entities have the same alignment requirements ([basic.align]),

if a has-attribute-expression ([cpp.cond]) is not 0 for the no_unique_address attribute, then neither entity is declared with the no_unique_address attribute ([dcl.attr.nouniqueaddr]), and

either both entities are bit-fields with the same width or neither is a bit-field.

[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]

28

#

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]).

29

#

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]).

30

#

In a standard-layout union with an active member of struct type T1, it is permitted to read a non-static data member m of another union member of struct type T2 provided 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 } }; // active member is t1return u.t2.c; // OK, as if u.t1.a were nominated} — end example]

[Note 10:

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

— end note]

31

#

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 11:

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]

[Note 12:

The object and its first subobject are pointer-interconvertible ([basic.compound], [expr.static.cast]).

— end note]

32

#

A data member description is a quintuple (T, N, A, W, NUA) describing the potential declaration of a non-static data member where

T is a type,

N is an identifier or ⊥,

A is an alignment or ⊥,

W is a bit-field width or ⊥, and

NUA is a boolean value.

Two data member descriptions are equal if each of their respective components are the same entities, are the same identifiers, have equal values, or are both ⊥.

[Note 13:

The components of a data member description describe a data member such that

its type is specified using the type given by T,

it is declared with the name given by N if N is not ⊥ and is otherwise unnamed,

it is declared with the alignment-specifier ([dcl.align]) given by alignas(A) if A is not ⊥ and is otherwise declared without an alignment-specifier,

it is a bit-field ([class.bit]) with the width given by W if W is not ⊥ and is otherwise not a bit-field, and

it is declared with the attribute no_unique_address ([dcl.attr.nouniqueaddr]) if NUA is true and is otherwise declared without that attribute.

Data member descriptions are represented by reflections ([basic.fundamental]) returned by std::meta::data_member_spec ([meta.reflection.define.aggregate]) and can be reified as data members of a class using std::meta::define_aggregate.

— end note]