Annex D (normative) Compatibility features [depr]

D.1 General [depr.general]

This Annex describes features of the C++ Standard that are specified for compatibility with existing implementations.
These are deprecated features, where deprecated is defined as: Normative for the current revision of C++, but having been identified as a candidate for removal from future revisions.
An implementation may declare library names and entities described in this Clause with the deprecated attribute.

D.2 Implicit capture of *this by reference [depr.capture.this]

For compatibility with prior revisions of C++, a lambda-expression with capture-default = ([expr.prim.lambda.capture]) may implicitly capture *this by reference.
[Example 1: struct X { int x; void foo(int n) { auto f = [=]() { x = n; }; // deprecated: x means this->x, not a copy thereof auto g = [=, this]() { x = n; }; // recommended replacement } }; — end example]

D.3 Array comparisons [depr.array.comp]

Equality and relational comparisons ([expr.eq], [expr.rel]) between two operands of array type are deprecated.
[Note 1: 
Three-way comparisons ([expr.spaceship]) between such operands are ill-formed.
— end note]
[Example 1: int arr1[5]; int arr2[5]; bool same = arr1 == arr2; // deprecated, same as &arr1[0] == &arr2[0], // does not compare array contents auto cmp = arr1 <=> arr2; // error — end example]

D.4 Deprecated volatile types [depr.volatile.type]

Postfix ++ and -- expressions ([expr.post.incr]) and prefix ++ and -- expressions ([expr.pre.incr]) of volatile-qualified arithmetic and pointer types are deprecated.
[Example 1: volatile int velociraptor; ++velociraptor; // deprecated — end example]
Certain assignments where the left operand is a volatile-qualified non-class type are deprecated; see [expr.ass].
[Example 2: int neck, tail; volatile int brachiosaur; brachiosaur = neck; // OK tail = brachiosaur; // OK tail = brachiosaur = neck; // deprecated brachiosaur += neck; // OK — end example]
A function type ([dcl.fct]) with a parameter with volatile-qualified type or with a volatile-qualified return type is deprecated.
[Example 3: volatile struct amber jurassic(); // deprecated void trex(volatile short left_arm, volatile short right_arm); // deprecated void fly(volatile struct pterosaur* pteranodon); // OK — end example]
A structured binding ([dcl.struct.bind]) of a volatile-qualified type is deprecated.
[Example 4: struct linhenykus { short forelimb; }; void park(linhenykus alvarezsauroid) { volatile auto [what_is_this] = alvarezsauroid; // deprecated // ... } — end example]

D.5 Redeclaration of static constexpr data members [depr.static.constexpr]

For compatibility with prior revisions of C++, a constexpr static data member may be redundantly redeclared outside the class with no initializer ([basic.def], [class.static.data]).
This usage is deprecated.
[Example 1: struct A { static constexpr int n = 5; // definition (declaration in C++ 2014) }; constexpr int A::n; // redundant declaration (definition in C++ 2014) — end example]

D.6 Non-local use of TU-local entities [depr.local]

A declaration of a non-TU-local entity that is an exposure ([basic.link]) is deprecated.
[Note 1: 
Such a declaration in an importable module unit is ill-formed.
— end note]
[Example 1: namespace { struct A { void f() {} }; } A h(); // deprecated: not internal linkage inline void g() {A().f();} // deprecated: inline and not internal linkage — end example]

D.7 Implicit declaration of copy functions [depr.impldec]

The implicit definition of a copy constructor as defaulted is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.
The implicit definition of a copy assignment operator as defaulted is deprecated if the class has a user-declared copy constructor or a user-declared destructor.
It is possible that future versions of C++ will specify that these implicit definitions are deleted ([dcl.fct.def.delete]).

D.8 Literal operator function declarations using an identifier [depr.lit]

A literal-operator-id ([over.literal]) of the form operator string-literal identifier is deprecated.

D.9 template keyword before qualified names [depr.template.template]

The use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated ([temp.names]).

D.10 has_denorm members in numeric_limits [depr.numeric.limits.has.denorm]

The following type is defined in addition to those specified in <limits>: namespace std { enum float_denorm_style { denorm_indeterminate = -1, denorm_absent = 0, denorm_present = 1 }; }
The following members are defined in addition to those specified in [numeric.limits.general]: static constexpr float_denorm_style has_denorm = denorm_absent; static constexpr bool has_denorm_loss = false;
The values of has_denorm and has_denorm_loss of specializations of numeric_limits are unspecified.
The following members of the specialization numeric_limits<bool> are defined in addition to those specified in [numeric.special]: static constexpr float_denorm_style has_denorm = denorm_absent; static constexpr bool has_denorm_loss = false;

D.11 Deprecated C macros [depr.c.macros]

The header <stdalign.h> has the following macro: #define __alignas_is_defined 1
The header <stdbool.h> has the following macro: #define __bool_true_false_are_defined 1

D.12 Relational operators [depr.relops]

The header <utility> has the following additions: namespace std::rel_ops { template<class T> bool operator!=(const T&, const T&); template<class T> bool operator> (const T&, const T&); template<class T> bool operator<=(const T&, const T&); template<class T> bool operator>=(const T&, const T&); }
To avoid redundant definitions of operator!= out of operator== and operators >, <=, and >= out of operator<, the library provides the following:
template<class T> bool operator!=(const T& x, const T& y);
Preconditions: T meets the Cpp17EqualityComparable requirements (Table 28).
Returns: !(x == y).
template<class T> bool operator>(const T& x, const T& y);
Preconditions: T meets the Cpp17LessThanComparable requirements (Table 29).
Returns: y < x.
template<class T> bool operator<=(const T& x, const T& y);
Preconditions: T meets the Cpp17LessThanComparable requirements (Table 29).
Returns: !(y < x).
template<class T> bool operator>=(const T& x, const T& y);
Preconditions: T meets the Cpp17LessThanComparable requirements (Table 29).
Returns: !(x < y).

D.13 char* streams [depr.str.strstreams]

D.13.1 Header <strstream> synopsis [depr.strstream.syn]

The header <strstream> defines types that associate stream buffers with character array objects and assist reading and writing such objects.
namespace std { class strstreambuf; class istrstream; class ostrstream; class strstream; }

D.13.2 Class strstreambuf [depr.strstreambuf]

D.13.2.1 General [depr.strstreambuf.general]

namespace std { class strstreambuf : public basic_streambuf<char> { public: strstreambuf() : strstreambuf(0) {} explicit strstreambuf(streamsize alsize_arg); strstreambuf(void* (*palloc_arg)(size_t), void (*pfree_arg)(void*)); strstreambuf(char* gnext_arg, streamsize n, char* pbeg_arg = nullptr); strstreambuf(const char* gnext_arg, streamsize n); strstreambuf(signed char* gnext_arg, streamsize n, signed char* pbeg_arg = nullptr); strstreambuf(const signed char* gnext_arg, streamsize n); strstreambuf(unsigned char* gnext_arg, streamsize n, unsigned char* pbeg_arg = nullptr); strstreambuf(const unsigned char* gnext_arg, streamsize n); virtual ~strstreambuf(); void freeze(bool freezefl = true); char* str(); int pcount(); protected: int_type overflow (int_type c = EOF) override; int_type pbackfail(int_type c = EOF) override; int_type underflow() override; pos_type seekoff(off_type off, ios_base::seekdir way, ios_base::openmode which = ios_base::in | ios_base::out) override; pos_type seekpos(pos_type sp, ios_base::openmode which = ios_base::in | ios_base::out) override; streambuf* setbuf(char* s, streamsize n) override; private: using strstate = T1; // exposition only static const strstate allocated; // exposition only static const strstate constant; // exposition only static const strstate dynamic; // exposition only static const strstate frozen; // exposition only strstate strmode; // exposition only streamsize alsize; // exposition only void* (*palloc)(size_t); // exposition only void (*pfree)(void*); // exposition only }; }
The class strstreambuf associates the input sequence, and possibly the output sequence, with an object of some character array type, whose elements store arbitrary values.
The array object has several attributes.
[Note 1: 
For the sake of exposition, these are represented as elements of a bitmask type (indicated here as T1) called strstate.
The elements are:
  • allocated, set when a dynamic array object has been allocated, and hence will be freed by the destructor for the strstreambuf object;
  • constant, set when the array object has const elements, so the output sequence cannot be written;
  • dynamic, set when the array object is allocated (or reallocated) as necessary to hold a character sequence that can change in length;
  • frozen, set when the program has requested that the array object not be altered, reallocated, or freed.
— end note]
[Note 2: 
For the sake of exposition, the maintained data is presented here as:
  • strstate strmode, the attributes of the array object associated with the strstreambuf object;
  • int alsize, the suggested minimum size for a dynamic array object;
  • void* (*palloc)(size_t), points to the function to call to allocate a dynamic array object;
  • void (*pfree)(void*), points to the function to call to free a dynamic array object.
— end note]
Each object of class strstreambuf has a seekable area, delimited by the pointers seeklow and seekhigh.
If gnext is a null pointer, the seekable area is undefined.
Otherwise, seeklow equals gbeg and seekhigh is either pend, if pend is not a null pointer, or gend.

D.13.2.2 strstreambuf constructors [depr.strstreambuf.cons]

explicit strstreambuf(streamsize alsize_arg);
Effects: Initializes the base class with streambuf().
The postconditions of this function are indicated in Table 147.
Table 147: strstreambuf(streamsize) effects [tab:depr.strstreambuf.cons.sz]
Element
Value
strmode
dynamic
alsize
alsize_arg
palloc
a null pointer
pfree
a null pointer
strstreambuf(void* (*palloc_arg)(size_t), void (*pfree_arg)(void*));
Effects: Initializes the base class with streambuf().
The postconditions of this function are indicated in Table 148.
Table 148: strstreambuf(void* (*)(size_t), void (*)(void*)) effects [tab:depr.strstreambuf.cons.alloc]
Element
Value
strmode
dynamic
alsize
an unspecified value
palloc
palloc_arg
pfree
pfree_arg
strstreambuf(char* gnext_arg, streamsize n, char* pbeg_arg = nullptr); strstreambuf(signed char* gnext_arg, streamsize n, signed char* pbeg_arg = nullptr); strstreambuf(unsigned char* gnext_arg, streamsize n, unsigned char* pbeg_arg = nullptr);
Effects: Initializes the base class with streambuf().
The postconditions of this function are indicated in Table 149.
Table 149: strstreambuf(charT*, streamsize, charT*) effects [tab:depr.strstreambuf.cons.ptr]
Element
Value
strmode
0
alsize
an unspecified value
palloc
a null pointer
pfree
a null pointer
gnext_arg shall point to the first element of an array object whose number of elements N is determined as follows:
If pbeg_arg is a null pointer, the function executes: setg(gnext_arg, gnext_arg, gnext_arg + N);
Otherwise, the function executes: setg(gnext_arg, gnext_arg, pbeg_arg); setp(pbeg_arg, pbeg_arg + N);
strstreambuf(const char* gnext_arg, streamsize n); strstreambuf(const signed char* gnext_arg, streamsize n); strstreambuf(const unsigned char* gnext_arg, streamsize n);
Effects: Behaves the same as strstreambuf((char*)gnext_arg,n), except that the constructor also sets constant in strmode.
virtual ~strstreambuf();
Effects: Destroys an object of class strstreambuf.
The function frees the dynamically allocated array object only if (strmode & allocated) != 0 and (strmode & frozen) == 0.
([depr.strstreambuf.virtuals] describes how a dynamically allocated array object is freed.)
305)305)
The function signature strlen(const char*) is declared in <cstring>.
The macro INT_MAX is defined in <climits>.

D.13.2.3 Member functions [depr.strstreambuf.members]

void freeze(bool freezefl = true);
Effects: If strmode & dynamic is nonzero, alters the freeze status of the dynamic array object as follows:
  • If freezefl is true, the function sets frozen in strmode.
  • Otherwise, it clears frozen in strmode.
char* str();
Effects: Calls freeze(), then returns the beginning pointer for the input sequence, gbeg.
Remarks: The return value can be a null pointer.
int pcount() const;
Effects: If the next pointer for the output sequence, pnext, is a null pointer, returns zero.
Otherwise, returns the current effective length of the array object as the next pointer minus the beginning pointer for the output sequence, pnext - pbeg.

D.13.2.4 strstreambuf overridden virtual functions [depr.strstreambuf.virtuals]

int_type overflow(int_type c = EOF) override;
Effects: Appends the character designated by c to the output sequence, if possible, in one of two ways:
  • If c != EOF and if either the output sequence has a write position available or the function makes a write position available (as described below), assigns c to *pnext++.
    Returns (unsigned char)c.
  • If c == EOF, there is no character to append.
    Returns a value other than EOF.
Returns EOF to indicate failure.
Remarks: The function can alter the number of write positions available as a result of any call.
To make a write position available, the function reallocates (or initially allocates) an array object with a sufficient number of elements n to hold the current array object (if any), plus at least one additional write position.
How many additional write positions are made available is otherwise unspecified.
If palloc is not a null pointer, the function calls (*palloc)(n) to allocate the new dynamic array object.
Otherwise, it evaluates the expression new charT[n].
In either case, if the allocation fails, the function returns EOF.
Otherwise, it sets allocated in strmode.
To free a previously existing dynamic array object whose first element address is p: If pfree is not a null pointer, the function calls (*pfree)(p).
Otherwise, it evaluates the expression delete[]p.
If (strmode & dynamic) == 0, or if (strmode & frozen) != 0, the function cannot extend the array (reallocate it with greater length) to make a write position available.
Recommended practice: An implementation should consider alsize in making the decision how many additional write positions to make available.
int_type pbackfail(int_type c = EOF) override;
Puts back the character designated by c to the input sequence, if possible, in one of three ways:
  • If c != EOF, if the input sequence has a putback position available, and if (char)c == gnext[-1], assigns gnext - 1 to gnext.
    Returns c.
  • If c != EOF, if the input sequence has a putback position available, and if strmode & constant is zero, assigns c to *--gnext.
    Returns c.
  • If c == EOF and if the input sequence has a putback position available, assigns gnext - 1 to gnext.
    Returns a value other than EOF.
Returns EOF to indicate failure.
Remarks: If the function can succeed in more than one of these ways, it is unspecified which way is chosen.
The function can alter the number of putback positions available as a result of any call.
int_type underflow() override;
Effects: Reads a character from the input sequence, if possible, without moving the stream position past it, as follows:
  • If the input sequence has a read position available, the function signals success by returning (unsigned char)*gnext.
  • Otherwise, if the current write next pointer pnext is not a null pointer and is greater than the current read end pointer gend, makes a read position available by assigning to gend a value greater than gnext and no greater than pnext.
    Returns (unsigned char)*gnext.
Returns EOF to indicate failure.
Remarks: The function can alter the number of read positions available as a result of any call.
pos_type seekoff(off_type off, seekdir way, openmode which = in | out) override;
Effects: Alters the stream position within one of the controlled sequences, if possible, as indicated in Table 150.
Table 150: seekoff positioning [tab:depr.strstreambuf.seekoff.pos]
Conditions
Result
(which & ios​::​in) != 0
positions the input sequence
(which & ios​::​out) != 0
positions the output sequence
(which & (ios​::​in | ios​::​out)) ==
(ios​::​in | ios​::​out) and either
way == ios​::​beg or way == ios​::​end
positions both the input and the output sequences
Otherwise
the positioning operation fails.
For a sequence to be positioned, if its next pointer is a null pointer, the positioning operation fails.
Otherwise, the function determines newoff as indicated in Table 151.
Table 151: newoff values [tab:depr.strstreambuf.seekoff.newoff]
Condition
newoff Value
way == ios​::​beg
0
way == ios​::​cur
the next pointer minus the beginning pointer (xnext - xbeg).
way == ios​::​end
seekhigh minus the beginning pointer (seekhigh - xbeg).
If (newoff + off) < (seeklow - xbeg) or (seekhigh - xbeg) < (newoff + off), the positioning operation fails.
Otherwise, the function assigns xbeg + newoff + off to the next pointer xnext.
Returns: pos_type(newoff), constructed from the resultant offset newoff (of type off_type), that stores the resultant stream position, if possible.
If the positioning operation fails, or if the constructed object cannot represent the resultant stream position, the return value is pos_type(off_type(-1)).
pos_type seekpos(pos_type sp, ios_base::openmode which = ios_base::in | ios_base::out) override;
Effects: Alters the stream position within one of the controlled sequences, if possible, to correspond to the stream position stored in sp (as described below).
  • If (which & ios​::​in) != 0, positions the input sequence.
  • If (which & ios​::​out) != 0, positions the output sequence.
  • If the function positions neither sequence, the positioning operation fails.
For a sequence to be positioned, if its next pointer is a null pointer, the positioning operation fails.
Otherwise, the function determines newoff from sp.offset():
  • If newoff is an invalid stream position, has a negative value, or has a value greater than (seekhigh - seeklow), the positioning operation fails
  • Otherwise, the function adds newoff to the beginning pointer xbeg and stores the result in the next pointer xnext.
Returns: pos_type(newoff), constructed from the resultant offset newoff (of type off_type), that stores the resultant stream position, if possible.
If the positioning operation fails, or if the constructed object cannot represent the resultant stream position, the return value is pos_type(off_type(-1)).
streambuf<char>* setbuf(char* s, streamsize n) override;
Effects: Behavior is implementation-defined, except that setbuf(0, 0) has no effect.

D.13.3 Class istrstream [depr.istrstream]

D.13.3.1 General [depr.istrstream.general]

namespace std { class istrstream : public basic_istream<char> { public: explicit istrstream(const char* s); explicit istrstream(char* s); istrstream(const char* s, streamsize n); istrstream(char* s, streamsize n); virtual ~istrstream(); strstreambuf* rdbuf() const; char* str(); private: strstreambuf sb; // exposition only }; }
The class istrstream supports the reading of objects of class strstreambuf.
It supplies a strstreambuf object to control the associated array object.
For the sake of exposition, the maintained data is presented here as:
  • sb, the strstreambuf object.

D.13.3.2 istrstream constructors [depr.istrstream.cons]

explicit istrstream(const char* s); explicit istrstream(char* s);
Effects: Initializes the base class with istream(&sb) and sb with strstreambuf(s, 0).
s shall designate the first element of an ntbs.
istrstream(const char* s, streamsize n); istrstream(char* s, streamsize n);
Effects: Initializes the base class with istream(&sb) and sb with strstreambuf(s, n).
s shall designate the first element of an array whose length is n elements, and n shall be greater than zero.

D.13.3.3 Member functions [depr.istrstream.members]

strstreambuf* rdbuf() const;
Returns: const_cast<strstreambuf*>(&sb).
char* str();
Returns: rdbuf()->str().

D.13.4 Class ostrstream [depr.ostrstream]

D.13.4.1 General [depr.ostrstream.general]

namespace std { class ostrstream : public basic_ostream<char> { public: ostrstream(); ostrstream(char* s, int n, ios_base::openmode mode = ios_base::out); virtual ~ostrstream(); strstreambuf* rdbuf() const; void freeze(bool freezefl = true); char* str(); int pcount() const; private: strstreambuf sb; // exposition only }; }
The class ostrstream supports the writing of objects of class strstreambuf.
It supplies a strstreambuf object to control the associated array object.
For the sake of exposition, the maintained data is presented here as:
  • sb, the strstreambuf object.

D.13.4.2 ostrstream constructors [depr.ostrstream.cons]

ostrstream();
Effects: Initializes the base class with ostream(&sb) and sb with strstreambuf().
ostrstream(char* s, int n, ios_base::openmode mode = ios_base::out);
Effects: Initializes the base class with ostream(&sb), and sb with one of two constructors:
  • If (mode & app) == 0, then s shall designate the first element of an array of n elements.
    The constructor is strstreambuf(s, n, s).
  • If (mode & app) != 0, then s shall designate the first element of an array of n elements that contains an ntbs whose first element is designated by s.
    The constructor is strstreambuf(s, n, s + std​::​strlen(s)).306
306)306)
The function signature strlen(const char*) is declared in <cstring>.

D.13.4.3 Member functions [depr.ostrstream.members]

strstreambuf* rdbuf() const;
Returns: (strstreambuf*)&sb.
void freeze(bool freezefl = true);
Effects: Calls rdbuf()->freeze(freezefl).
char* str();
Returns: rdbuf()->str().
int pcount() const;
Returns: rdbuf()->pcount().

D.13.5 Class strstream [depr.strstream]

D.13.5.1 General [depr.strstream.general]

namespace std { class strstream : public basic_iostream<char> { public: // types using char_type = char; using int_type = char_traits<char>::int_type; using pos_type = char_traits<char>::pos_type; using off_type = char_traits<char>::off_type; // constructors/destructor strstream(); strstream(char* s, int n, ios_base::openmode mode = ios_base::in|ios_base::out); virtual ~strstream(); // members strstreambuf* rdbuf() const; void freeze(bool freezefl = true); int pcount() const; char* str(); private: strstreambuf sb; // exposition only }; }
The class strstream supports reading and writing from objects of class strstreambuf.
It supplies a strstreambuf object to control the associated array object.
For the sake of exposition, the maintained data is presented here as:
  • sb, the strstreambuf object.

D.13.5.2 strstream constructors [depr.strstream.cons]

strstream();
Effects: Initializes the base class with iostream(&sb).
strstream(char* s, int n, ios_base::openmode mode = ios_base::in|ios_base::out);
Effects: Initializes the base class with iostream(&sb), and sb with one of the two constructors:
  • If (mode & app) == 0, then s shall designate the first element of an array of n elements.
    The constructor is strstreambuf(s,n,s).
  • If (mode & app) != 0, then s shall designate the first element of an array of n elements that contains an ntbs whose first element is designated by s.
    The constructor is strstreambuf(s,n,s + std​::​strlen(s)).

D.13.5.3 strstream destructor [depr.strstream.dest]

virtual ~strstream();
Effects: Destroys an object of class strstream.

D.13.5.4 strstream operations [depr.strstream.oper]

strstreambuf* rdbuf() const;
Returns: const_cast<strstreambuf*>(&sb).
void freeze(bool freezefl = true);
Effects: Calls rdbuf()->freeze(freezefl).
char* str();
Returns: rdbuf()->str().
int pcount() const;
Returns: rdbuf()->pcount().

D.14 Deprecated error numbers [depr.cerrno]

The following macros are defined in addition to those specified in [cerrno.syn]:
#define ENODATA see below #define ENOSR see below #define ENOSTR see below #define ETIME see below
The meaning of these macros is defined by the POSIX standard.
The following enum errc enumerators are defined in addition to those specified in [system.error.syn]:
no_message_available, // ENODATA no_stream_resources, // ENOSR not_a_stream, // ENOSTR stream_timeout, // ETIME
The value of each enum errc enumerator above is the same as the value of the <cerrno> macro shown in the above synopsis.

D.15 Deprecated polymorphic_allocator member function [depr.mem.poly.allocator.mem]

The following member is declared in addition to those members specified in [mem.poly.allocator.mem]:
namespace std::pmr { template<class Tp = byte> class polymorphic_allocator { public: template <class T> void destroy(T* p); }; }
template<class T> void destroy(T* p);
Effects: As if by p->~T().

D.16 Deprecated type traits [depr.meta.types]

The header <type_traits> has the following addition: namespace std { template<class T> struct is_pod; template<class T> constexpr bool is_pod_v = is_pod<T>::value; template<size_t Len, size_t Align = default-alignment> // see below struct aligned_storage; template<size_t Len, size_t Align = default-alignment> // see below using aligned_storage_t = typename aligned_storage<Len, Align>::type; template<size_t Len, class... Types> struct aligned_union; template<size_t Len, class... Types> using aligned_union_t = typename aligned_union<Len, Types...>::type; }
The behavior of a program that adds specializations for any of the templates defined in this subclause is undefined, unless explicitly permitted by the specification of the corresponding template.
A POD class is a class that is both a trivial class and a standard-layout class, and has no non-static data members of type non-POD class (or array thereof).
A POD type is a scalar type, a POD class, an array of such a type, or a cv-qualified version of one of these types.
template<class T> struct is_pod;
Preconditions: remove_all_extents_t<T> shall be a complete type or cv void.
Remarks: is_pod<T> is a Cpp17UnaryTypeTrait ([meta.rqmts]) with a base characteristic of true_type if T is a POD type, and false_type otherwise.
[Note 1: 
It is unspecified whether a closure type ([expr.prim.lambda.closure]) is a POD type.
— end note]
template<size_t Len, size_t Align = default-alignment> struct aligned_storage;
The value of default-alignment is the most stringent alignment requirement for any object type whose size is no greater than Len ([basic.types]).
Mandates: Len is not zero.
Align is equal to alignof(T) for some type T or to default-alignment.
The member typedef type denotes a trivial standard-layout type suitable for use as uninitialized storage for any object whose size is at most Len and whose alignment is a divisor of Align.
[Note 2: 
Uses of aligned_storage<Len, Align>​::​type can be replaced by an array std​::​byte[Len] declared with alignas(Align).
— end note]
[Note 3: 
A typical implementation would define aligned_storage as: template<size_t Len, size_t Alignment> struct aligned_storage { typedef struct { alignas(Alignment) unsigned char __data[Len]; } type; };
— end note]
template<size_t Len, class... Types> struct aligned_union;
Mandates: At least one type is provided.
Each type in the template parameter pack Types is a complete object type.
The member typedef type denotes a trivial standard-layout type suitable for use as uninitialized storage for any object whose type is listed in Types; its size shall be at least Len.
The static member alignment_value is an integral constant of type size_t whose value is the strictest alignment of all types listed in Types.

D.17 Tuple [depr.tuple]

The header <tuple> has the following additions: namespace std { template<class T> struct tuple_size<volatile T>; template<class T> struct tuple_size<const volatile T>; template<size_t I, class T> struct tuple_element<I, volatile T>; template<size_t I, class T> struct tuple_element<I, const volatile T>; }
template<class T> struct tuple_size<volatile T>; template<class T> struct tuple_size<const volatile T>;
Let TS denote tuple_size<T> of the cv-unqualified type T.
If the expression TS​::​value is well-formed when treated as an unevaluated operand, then specializations of each of the two templates meet the Cpp17TransformationTrait requirements with a base characteristic of integral_constant<size_t, TS​::​value>.
Otherwise, they have no member value.
Access checking is performed as if in a context unrelated to TS and T.
Only the validity of the immediate context of the expression is considered.
In addition to being available via inclusion of the <tuple> header, the two templates are available when any of the headers <array>, <ranges>, or <utility> are included.
template<size_t I, class T> struct tuple_element<I, volatile T>; template<size_t I, class T> struct tuple_element<I, const volatile T>;
Let TE denote tuple_element_t<I, T> of the cv-unqualified type T.
Then specializations of each of the two templates meet the Cpp17TransformationTrait requirements with a member typedef type that names the following type:
  • for the first specialization, add_volatile_t<TE>, and
  • for the second specialization, add_cv_t<TE>.
In addition to being available via inclusion of the <tuple> header, the two templates are available when any of the headers <array>, <ranges>, or <utility> are included.

D.18 Variant [depr.variant]

The header <variant> has the following additions: namespace std { template<class T> struct variant_size<volatile T>; template<class T> struct variant_size<const volatile T>; template<size_t I, class T> struct variant_alternative<I, volatile T>; template<size_t I, class T> struct variant_alternative<I, const volatile T>; }
template<class T> struct variant_size<volatile T>; template<class T> struct variant_size<const volatile T>;
Let VS denote variant_size<T> of the cv-unqualified type T.
Then specializations of each of the two templates meet the Cpp17UnaryTypeTrait requirements with a base characteristic of integral_constant<size_t, VS​::​value>.
template<size_t I, class T> struct variant_alternative<I, volatile T>; template<size_t I, class T> struct variant_alternative<I, const volatile T>;
Let VA denote variant_alternative<I, T> of the cv-unqualified type T.
Then specializations of each of the two templates meet the Cpp17TransformationTrait requirements with a member typedef type that names the following type:
  • for the first specialization, add_volatile_t<VA​::​type>, and
  • for the second specialization, add_cv_t<VA​::​type>.

D.19 Deprecated iterator class template [depr.iterator]

The header <iterator> has the following addition: namespace std { template<class Category, class T, class Distance = ptrdiff_t, class Pointer = T*, class Reference = T&> struct iterator { using iterator_category = Category; using value_type = T; using difference_type = Distance; using pointer = Pointer; using reference = Reference; }; }
The iterator template may be used as a base class to ease the definition of required types for new iterators.
[Note 1: 
If the new iterator type is a class template, then these aliases will not be visible from within the iterator class's template definition, but only to callers of that class.
— end note]
[Example 1: 
If a C++ program wants to define a bidirectional iterator for some data structure containing double and such that it works on a large memory model of the implementation, it can do so with: class MyIterator : public iterator<bidirectional_iterator_tag, double, long, T*, T&> { // code implementing ++, etc. };
— end example]

D.20 Deprecated move_iterator access [depr.move.iter.elem]

The following member is declared in addition to those members specified in [move.iter.elem]: namespace std { template<class Iterator> class move_iterator { public: constexpr pointer operator->() const; }; }
constexpr pointer operator->() const;
Returns: current.

D.21 Deprecated shared_ptr atomic access [depr.util.smartptr.shared.atomic]

The header <memory> has the following additions: namespace std { template<class T> bool atomic_is_lock_free(const shared_ptr<T>* p); template<class T> shared_ptr<T> atomic_load(const shared_ptr<T>* p); template<class T> shared_ptr<T> atomic_load_explicit(const shared_ptr<T>* p, memory_order mo); template<class T> void atomic_store(shared_ptr<T>* p, shared_ptr<T> r); template<class T> void atomic_store_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo); template<class T> shared_ptr<T> atomic_exchange(shared_ptr<T>* p, shared_ptr<T> r); template<class T> shared_ptr<T> atomic_exchange_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo); template<class T> bool atomic_compare_exchange_weak(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w); template<class T> bool atomic_compare_exchange_strong(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w); template<class T> bool atomic_compare_exchange_weak_explicit( shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w, memory_order success, memory_order failure); template<class T> bool atomic_compare_exchange_strong_explicit( shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w, memory_order success, memory_order failure); }
Concurrent access to a shared_ptr object from multiple threads does not introduce a data race if the access is done exclusively via the functions in this subclause and the instance is passed as their first argument.
The meaning of the arguments of type memory_order is explained in [atomics.order].
template<class T> bool atomic_is_lock_free(const shared_ptr<T>* p);
Preconditions: p is not null.
Returns: true if atomic access to *p is lock-free, false otherwise.
Throws: Nothing.
template<class T> shared_ptr<T> atomic_load(const shared_ptr<T>* p);
Preconditions: p is not null.
Returns: atomic_load_explicit(p, memory_order​::​seq_cst).
Throws: Nothing.
template<class T> shared_ptr<T> atomic_load_explicit(const shared_ptr<T>* p, memory_order mo);
Preconditions: p is not null.
mo is neither memory_order​::​release nor memory_order​::​acq_rel.
Returns: *p.
Throws: Nothing.
template<class T> void atomic_store(shared_ptr<T>* p, shared_ptr<T> r);
Preconditions: p is not null.
Effects: As if by atomic_store_explicit(p, r, memory_order​::​seq_cst).
Throws: Nothing.
template<class T> void atomic_store_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);
Preconditions: p is not null.
mo is neither memory_order​::​acquire nor memory_order​::​acq_rel.
Effects: As if by p->swap(r).
Throws: Nothing.
template<class T> shared_ptr<T> atomic_exchange(shared_ptr<T>* p, shared_ptr<T> r);
Preconditions: p is not null.
Returns: atomic_exchange_explicit(p, r, memory_order​::​seq_cst).
Throws: Nothing.
template<class T> shared_ptr<T> atomic_exchange_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);
Preconditions: p is not null.
Effects: As if by p->swap(r).
Returns: The previous value of *p.
Throws: Nothing.
template<class T> bool atomic_compare_exchange_weak(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);
Preconditions: p is not null and v is not null.
Returns: atomic_compare_exchange_weak_explicit(p, v, w, memory_order::seq_cst, memory_order::seq_cst)
Throws: Nothing.
template<class T> bool atomic_compare_exchange_strong(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);
Returns: atomic_compare_exchange_strong_explicit(p, v, w, memory_order::seq_cst, memory_order::seq_cst)
template<class T> bool atomic_compare_exchange_weak_explicit( shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w, memory_order success, memory_order failure); template<class T> bool atomic_compare_exchange_strong_explicit( shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w, memory_order success, memory_order failure);
Preconditions: p is not null and v is not null.
The failure argument is neither memory_order​::​release nor memory_order​::​acq_rel.
Effects: If *p is equivalent to *v, assigns w to *p and has synchronization semantics corresponding to the value of success, otherwise assigns *p to *v and has synchronization semantics corresponding to the value of failure.
Returns: true if *p was equivalent to *v, false otherwise.
Throws: Nothing.
Remarks: Two shared_ptr objects are equivalent if they store the same pointer value and share ownership.
The weak form may fail spuriously.

D.22 Deprecated formatting [depr.format]

D.22.1 Header <format> synopsis [depr.format.syn]

The header <format>format.syn has the following additions: namespace std { template<class Visitor, class Context> decltype(auto) visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg); }

D.22.2 Formatting arguments [depr.format.arg]

template<class Visitor, class Context> decltype(auto) visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
Effects: Equivalent to: return visit(std​::​forward<Visitor>(vis), arg.value);

D.23 Deprecated convenience conversion interfaces [depr.conversions]

D.23.1 General [depr.conversions.general]

The header <locale> has the following additions: namespace std { template<class Codecvt, class Elem = wchar_t, class WideAlloc = allocator<Elem>, class ByteAlloc = allocator<char>> class wstring_convert; template<class Codecvt, class Elem = wchar_t, class Tr = char_traits<Elem>> class wbuffer_convert; }

D.23.2 Class template wstring_convert [depr.conversions.string]

Class template wstring_convert performs conversions between a wide string and a byte string.
It lets you specify a code conversion facet (like class template codecvt) to perform the conversions, without affecting any streams or locales.
[Example 1: 
If you want to use a code conversion facet, codecvt_for_utf8, to output to cout a UTF-8 multibyte sequence corresponding to a wide string, but you don't want to alter the locale for cout, you can write something like: std::wstring_convert<codecvt_for_utf8<wchar_t>> myconv; std::string mbstring = myconv.to_bytes(L"Hello\n"); std::cout << mbstring;
— end example]
namespace std { template<class Codecvt, class Elem = wchar_t, class WideAlloc = allocator<Elem>, class ByteAlloc = allocator<char>> class wstring_convert { public: using byte_string = basic_string<char, char_traits<char>, ByteAlloc>; using wide_string = basic_string<Elem, char_traits<Elem>, WideAlloc>; using state_type = typename Codecvt::state_type; using int_type = typename wide_string::traits_type::int_type; wstring_convert() : wstring_convert(new Codecvt) {} explicit wstring_convert(Codecvt* pcvt); wstring_convert(Codecvt* pcvt, state_type state); explicit wstring_convert(const byte_string& byte_err, const wide_string& wide_err = wide_string()); ~wstring_convert(); wstring_convert(const wstring_convert&) = delete; wstring_convert& operator=(const wstring_convert&) = delete; wide_string from_bytes(char byte); wide_string from_bytes(const char* ptr); wide_string from_bytes(const byte_string& str); wide_string from_bytes(const char* first, const char* last); byte_string to_bytes(Elem wchar); byte_string to_bytes(const Elem* wptr); byte_string to_bytes(const wide_string& wstr); byte_string to_bytes(const Elem* first, const Elem* last); size_t converted() const noexcept; state_type state() const; private: byte_string byte_err_string; // exposition only wide_string wide_err_string; // exposition only Codecvt* cvtptr; // exposition only state_type cvtstate; // exposition only size_t cvtcount; // exposition only }; }
The class template describes an object that controls conversions between wide string objects of class basic_string<Elem, char_traits<Elem>, WideAlloc> and byte string objects of class basic_string<char, char_traits<char>, ByteAlloc>.
The class template defines the types wide_string and byte_string as synonyms for these two types.
Conversion between a sequence of Elem values (stored in a wide_string object) and multibyte sequences (stored in a byte_string object) is performed by an object of class Codecvt, which meets the requirements of the standard code-conversion facet codecvt<Elem, char, mbstate_t>.
An object of this class template stores:
  • byte_err_string — a byte string to display on errors
  • wide_err_string — a wide string to display on errors
  • cvtptr — a pointer to the allocated conversion object (which is freed when the wstring_convert object is destroyed)
  • cvtstate — a conversion state object
  • cvtcount — a conversion count
size_t converted() const noexcept;
Returns: cvtcount.
wide_string from_bytes(char byte); wide_string from_bytes(const char* ptr); wide_string from_bytes(const byte_string& str); wide_string from_bytes(const char* first, const char* last);
Effects: The first member function converts the single-element sequence byte to a wide string.
The second member function converts the null-terminated sequence beginning at ptr to a wide string.
The third member function converts the sequence stored in str to a wide string.
The fourth member function converts the sequence defined by the range [first, last) to a wide string.
In all cases:
  • If the cvtstate object was not constructed with an explicit value, it is set to its default value (the initial conversion state) before the conversion begins.
    Otherwise it is left unchanged.
  • The number of input elements successfully converted is stored in cvtcount.
Returns: If no conversion error occurs, the member function returns the converted wide string.
Otherwise, if the object was constructed with a wide-error string, the member function returns the wide-error string.
Otherwise, the member function throws an object of class range_error.
state_type state() const;
Returns: cvtstate.
byte_string to_bytes(Elem wchar); byte_string to_bytes(const Elem* wptr); byte_string to_bytes(const wide_string& wstr); byte_string to_bytes(const Elem* first, const Elem* last);
Effects: The first member function converts the single-element sequence wchar to a byte string.
The second member function converts the null-terminated sequence beginning at wptr to a byte string.
The third member function converts the sequence stored in wstr to a byte string.
The fourth member function converts the sequence defined by the range [first, last) to a byte string.
In all cases:
  • If the cvtstate object was not constructed with an explicit value, it is set to its default value (the initial conversion state) before the conversion begins.
    Otherwise it is left unchanged.
  • The number of input elements successfully converted is stored in cvtcount.
Returns: If no conversion error occurs, the member function returns the converted byte string.
Otherwise, if the object was constructed with a byte-error string, the member function returns the byte-error string.
Otherwise, the member function throws an object of class range_error.
explicit wstring_convert(Codecvt* pcvt); wstring_convert(Codecvt* pcvt, state_type state); explicit wstring_convert(const byte_string& byte_err, const wide_string& wide_err = wide_string());
Preconditions: For the first and second constructors, pcvt is not null.
Effects: The first constructor stores pcvt in cvtptr and default values in cvtstate, byte_err_string, and wide_err_string.
The second constructor stores pcvt in cvtptr, state in cvtstate, and default values in byte_err_string and wide_err_string; moreover the stored state is retained between calls to from_bytes and to_bytes.
The third constructor stores new Codecvt in cvtptr, state_type() in cvtstate, byte_err in byte_err_string, and wide_err in wide_err_string.
~wstring_convert();
Effects: delete cvtptr.

D.23.3 Class template wbuffer_convert [depr.conversions.buffer]

Class template wbuffer_convert looks like a wide stream buffer, but performs all its I/O through an underlying byte stream buffer that you specify when you construct it.
Like class template wstring_convert, it lets you specify a code conversion facet to perform the conversions, without affecting any streams or locales.
namespace std { template<class Codecvt, class Elem = wchar_t, class Tr = char_traits<Elem>> class wbuffer_convert : public basic_streambuf<Elem, Tr> { public: using state_type = typename Codecvt::state_type; wbuffer_convert() : wbuffer_convert(nullptr) {} explicit wbuffer_convert(streambuf* bytebuf, Codecvt* pcvt = new Codecvt, state_type state = state_type()); ~wbuffer_convert(); wbuffer_convert(const wbuffer_convert&) = delete; wbuffer_convert& operator=(const wbuffer_convert&) = delete; streambuf* rdbuf() const; streambuf* rdbuf(streambuf* bytebuf); state_type state() const; private: streambuf* bufptr; // exposition only Codecvt* cvtptr; // exposition only state_type cvtstate; // exposition only }; }
The class template describes a stream buffer that controls the transmission of elements of type Elem, whose character traits are described by the class Tr, to and from a byte stream buffer of type streambuf.
Conversion between a sequence of Elem values and multibyte sequences is performed by an object of class Codecvt, which shall meet the requirements of the standard code-conversion facet codecvt<Elem, char, mbstate_t>.
An object of this class template stores:
  • bufptr — a pointer to its underlying byte stream buffer
  • cvtptr — a pointer to the allocated conversion object (which is freed when the wbuffer_convert object is destroyed)
  • cvtstate — a conversion state object
state_type state() const;
Returns: cvtstate.
streambuf* rdbuf() const;
Returns: bufptr.
streambuf* rdbuf(streambuf* bytebuf);
Effects: Stores bytebuf in bufptr.
Returns: The previous value of bufptr.
explicit wbuffer_convert( streambuf* bytebuf, Codecvt* pcvt = new Codecvt, state_type state = state_type());
Preconditions: pcvt is not null.
Effects: The constructor constructs a stream buffer object, initializes bufptr to bytebuf, initializes cvtptr to pcvt, and initializes cvtstate to state.
~wbuffer_convert();
Effects: delete cvtptr.

D.24 Deprecated locale category facets [depr.locale.category]

The ctype locale category includes the following facets as if they were specified in table Table 104 of [locale.category].
codecvt<char16_t, char, mbstate_t> codecvt<char32_t, char, mbstate_t>
The ctype locale category includes the following facets as if they were specified in table Table 105 of [locale.category].
codecvt_byname<char16_t, char, mbstate_t> codecvt_byname<char32_t, char, mbstate_t>
The following class template specializations are required in addition to those specified in [locale.codecvt].
The specialization codecvt<char16_t, char, mbstate_t> converts between the UTF-16 and UTF-8 encoding forms, and the specialization codecvt<char32_t, char, mbstate_t> converts between the UTF-32 and UTF-8 encoding forms.

D.25 Deprecated filesystem path factory functions [depr.fs.path.factory]

The header <filesystem> has the following additions:
template<class Source> path u8path(const Source& source); template<class InputIterator> path u8path(InputIterator first, InputIterator last);
Mandates: The value type of Source and InputIterator is char or char8_t.
Preconditions: The source and [first, last) sequences are UTF-8 encoded.
Source meets the requirements specified in [fs.path.req].
Returns:
  • If path​::​value_type is char and the current native narrow encoding ([fs.path.type.cvt]) is UTF-8, return path(source) or path(first, last); otherwise,
  • if path​::​value_type is wchar_t and the native wide encoding is UTF-16, or if path​::​value_type is char16_t or char32_t, convert source or [first, last) to a temporary, tmp, of type path​::​string_type and return path(tmp); otherwise,
  • convert source or [first, last) to a temporary, tmp, of type u32string and return path(tmp).
Remarks: Argument format conversion ([fs.path.fmt.cvt]) applies to the arguments for these functions.
How Unicode encoding conversions are performed is unspecified.
[Example 1: 
A string is to be read from a database that is encoded in UTF-8, and used to create a directory using the native encoding for filenames: namespace fs = std::filesystem; std::string utf8_string = read_utf8_data(); fs::create_directory(fs::u8path(utf8_string));
For POSIX-based operating systems with the native narrow encoding set to UTF-8, no encoding or type conversion occurs.
For POSIX-based operating systems with the native narrow encoding not set to UTF-8, a conversion to UTF-32 occurs, followed by a conversion to the current native narrow encoding.
Some Unicode characters may have no native character set representation.
For Windows-based operating systems a conversion from UTF-8 to UTF-16 occurs.
— end example]
[Note 1: 
The example above is representative of a historical use of filesystem​::​u8path.
To indicate a UTF-8 encoding, passing a std​::​u8string to path's constructor is preferred as it is consistent with path's handling of other encodings.
— end note]

D.26 Deprecated atomic operations [depr.atomics]

D.26.1 General [depr.atomics.general]

The header <atomic> has the following additions.
namespace std { template<class T> void atomic_init(volatile atomic<T>*, typename atomic<T>::value_type) noexcept; template<class T> void atomic_init(atomic<T>*, typename atomic<T>::value_type) noexcept; #define ATOMIC_VAR_INIT(value) see below }

D.26.2 Volatile access [depr.atomics.volatile]

If an atomic ([atomics.types.generic]) specialization has one of the following overloads, then that overload participates in overload resolution even if atomic<T>​::​is_always_lock_free is false: void store(T desired, memory_order order = memory_order::seq_cst) volatile noexcept; T operator=(T desired) volatile noexcept; T load(memory_order order = memory_order::seq_cst) const volatile noexcept; operator T() const volatile noexcept; T exchange(T desired, memory_order order = memory_order::seq_cst) volatile noexcept; bool compare_exchange_weak(T& expected, T desired, memory_order success, memory_order failure) volatile noexcept; bool compare_exchange_strong(T& expected, T desired, memory_order success, memory_order failure) volatile noexcept; bool compare_exchange_weak(T& expected, T desired, memory_order order = memory_order::seq_cst) volatile noexcept; bool compare_exchange_strong(T& expected, T desired, memory_order order = memory_order::seq_cst) volatile noexcept; T fetch_key(T operand, memory_order order = memory_order::seq_cst) volatile noexcept; T operator op=(T operand) volatile noexcept; T* fetch_key(ptrdiff_t operand, memory_order order = memory_order::seq_cst) volatile noexcept;

D.26.3 Non-member functions [depr.atomics.nonmembers]

template<class T> void atomic_init(volatile atomic<T>* object, typename atomic<T>::value_type desired) noexcept; template<class T> void atomic_init(atomic<T>* object, typename atomic<T>::value_type desired) noexcept;
Effects: Equivalent to: atomic_store_explicit(object, desired, memory_order​::​relaxed);

D.26.4 Operations on atomic types [depr.atomics.types.operations]

#define ATOMIC_VAR_INIT(value) see below
The macro expands to a token sequence suitable for constant initialization of an atomic variable of static storage duration of a type that is initialization-compatible with value.
[Note 1: 
This operation possibly needs to initialize locks.
— end note]
Concurrent access to the variable being initialized, even via an atomic operation, constitutes a data race.
[Example 1: atomic<int> v = ATOMIC_VAR_INIT(5); — end example]