Skip to content

Commit 291493b

Browse files
jensmaurertkoeppe
authored andcommitted
P2752R3 Static storage for braced initializers
1 parent 4bb1959 commit 291493b

File tree

3 files changed

+73
-17
lines changed

3 files changed

+73
-17
lines changed

source/compatibility.tex

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,36 @@
11
%!TEX root = std.tex
22
\infannex{diff}{Compatibility}
33

4+
\rSec1[diff.cpp23]{\Cpp{} and ISO \CppXXIII{}}
5+
6+
\rSec2[diff.cpp23.general]{General}
7+
8+
\pnum
9+
\indextext{summary!compatibility with ISO \CppXXIII{}}%
10+
Subclause \ref{diff.cpp23} lists the differences between \Cpp{} and
11+
ISO \CppXXIII{} (ISO/IEC 14882:2023, \doccite{Programming Languages --- \Cpp{}}),
12+
by the chapters of this document.
13+
14+
\rSec2[diff.cpp23.expr]{\ref{expr}: expressions}
15+
16+
\diffref{dcl.init.list}
17+
\change
18+
Pointer comparisons between \tcode{initializer_list} objects' backing arrays
19+
are unspecified.
20+
\rationale
21+
Permit the implementation to store backing arrays in static read-only memory.
22+
\effect
23+
Valid \CppXXIII{} code
24+
that relies on the result of pointer comparison between backing arrays
25+
may change behavior.
26+
For example:
27+
\begin{example}
28+
bool ne(std::initializer_list<int> a, std::initializer_list<int> b) {
29+
return a.begin() != b.begin() + 1;
30+
}
31+
bool b = ne({2,3}, {1,2,3}); // unspecified result; previously \tcode{false}
32+
\end{example}
33+
434
\rSec1[diff.cpp20]{\Cpp{} and ISO \CppXX{}}
535

636
\rSec2[diff.cpp20.general]{General}

source/declarations.tex

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5991,36 +5991,64 @@
59915991
an initializer list as if
59925992
the implementation generated and materialized\iref{conv.rval}
59935993
a prvalue of type ``array of $N$ \tcode{const E}'',
5994-
where $N$ is the number of elements in the
5995-
initializer list. Each element of that array is copy-initialized with the
5994+
where $N$ is the number of elements in the initializer list;
5995+
this is called the initializer list's \defnadj{backing}{array}.
5996+
Each element of the backing array is copy-initialized with the
59965997
corresponding element of the initializer list, and the
59975998
\tcode{std::initializer_list<E>} object is constructed to refer to that array.
59985999
\begin{note}
59996000
A constructor or conversion function selected for the copy is required to be
60006001
accessible\iref{class.access} in the context of the initializer list.
60016002
\end{note}
6002-
If a narrowing conversion is required to initialize any of the elements, the program is ill-formed.
6003+
If a narrowing conversion is required to initialize any of the elements,
6004+
the program is ill-formed.
6005+
Whether all backing arrays are distinct
6006+
(that is, are stored in non-overlapping objects) is unspecified.
6007+
6008+
\pnum
6009+
The backing array has the same lifetime as any other temporary
6010+
object\iref{class.temporary}, except that initializing an
6011+
\tcode{initializer_list} object from the array extends the lifetime of
6012+
the array exactly like binding a reference to a temporary.
60036013
\begin{example}
60046014
\begin{codeblock}
6005-
struct X {
6006-
X(std::initializer_list<double> v);
6015+
void f(std::initializer_list<double> il);
6016+
void g(float x) {
6017+
f({1, x, 3});
6018+
}
6019+
void h() {
6020+
f({1, 2, 3});
6021+
}
6022+
6023+
struct A {
6024+
mutable int i;
60076025
};
6008-
X x{ 1,2,3 };
6026+
void q(std::initializer_list<A>);
6027+
void r() {
6028+
q({A{1}, A{2}, A{3}});
6029+
}
60096030
\end{codeblock}
60106031

60116032
The initialization will be implemented in a way roughly equivalent to this:
60126033
\begin{codeblock}
6013-
const double __a[3] = {double{1}, double{2}, double{3}};
6014-
X x(std::initializer_list<double>(__a, __a+3));
6034+
void g(float x) {
6035+
const double __a[3] = {double{1}, double{x}, double{3}}; // backing array
6036+
f(std::initializer_list<double>(__a, __a+3));
6037+
}
6038+
void h() {
6039+
static constexpr double __b[3] = {double{1}, double{2}, double{3}}; // backing array
6040+
f(std::initializer_list<double>(__b, __b+3));
6041+
}
6042+
void r() {
6043+
const A __c[3] = {A{1}, A{2}, A{3}}; // backing array
6044+
q(std::initializer_list<A>(__c, __c+3));
6045+
}
60156046
\end{codeblock}
6016-
assuming that the implementation can construct an \tcode{initializer_list} object with a pair of pointers.
6047+
assuming that the implementation
6048+
can construct an \tcode{initializer_list} object with a pair of pointers, and
6049+
with the understanding that \tcode{__b} does not outlive the call to \tcode{f}.
60176050
\end{example}
60186051

6019-
\pnum
6020-
The array has the same lifetime as any other temporary
6021-
object\iref{class.temporary}, except that initializing an
6022-
\tcode{initiali\-zer_list} object from the array extends the lifetime of
6023-
the array exactly like binding a reference to a temporary.
60246052
\begin{example}
60256053
\begin{codeblock}
60266054
typedef std::complex<double> cmplx;
@@ -6047,9 +6075,6 @@
60476075
a temporary array to a reference member, so the program is
60486076
ill-formed\iref{class.base.init}.
60496077
\end{example}
6050-
\begin{note}
6051-
The implementation is free to allocate the array in read-only memory if an explicit array with the same initializer can be so allocated.
6052-
\end{note}
60536078

60546079
\pnum
60556080
A \defnadj{narrowing}{conversion} is an implicit conversion

source/macros.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@
274274
\newcommand{\CppXIV}{\Cpp{} 2014}
275275
\newcommand{\CppXVII}{\Cpp{} 2017}
276276
\newcommand{\CppXX}{\Cpp{} 2020}
277+
\newcommand{\CppXXIII}{\Cpp{} 2023}
277278
\newcommand{\opt}[1]{#1\ensuremath{_\mathit{\color{black}opt}}}
278279
\newcommand{\bigoh}[1]{\ensuremath{\mathscr{O}(#1)}}
279280

0 commit comments

Comments
 (0)