initializer_list
Section: 25.3.2 [range.access.begin], 25.3.3 [range.access.end], 25.3.6 [range.access.rbegin], 25.3.7 [range.access.rend] Status: Resolved Submitter: Casey Carter Opened: 2019-08-15 Last modified: 2021-06-23
Priority: 3
View all issues with Resolved status.
Discussion:
The specification of ranges::begin
in 25.3.2 [range.access.begin] includes a
"poison pill" overload:
which exists to create an ambiguity with the non-membertemplate<class T> void begin(initializer_list<T>&&) = delete;
initializer_list
overload of
begin
in namespace std
(17.10.2 [initializer.list.syn]) when performing
unqualified lookup, since specializations of initializer_list
should not satisfy
forwarding-range
(25.4.2 [range.range]). The design intent is that
const
specializations of initializer_list
should also not satisfy
forwarding-range
, although they are rare enough beasts that they were overlooked
when this wording is written.
ranges::end
(25.3.3 [range.access.end]) has a similar poison pill for
initializer_list
, which should be changed consistently.
Notably ranges::rbegin
(25.3.6 [range.access.rbegin]) and ranges::rend
(25.3.6 [range.access.rbegin]) as currently specified accept rvalue
initializer_list
arguments; they find the initializer_list
overloads of
std::rbegin
and std::rend
(24.7 [iterator.range]) via ADL. While I can't
put my finger on anything in particular that's broken by this behavior, it seems wise to make
rbegin
and rend
consistent with begin
and end
for
initializer_list
until and unless we discover a reason to do otherwise.
[2019-10 Priority set to 3 after reflector discussion]
[2021-06-23 Resolved by adoption of P2091R0 in Prague. Status changed: New → Resolved.]
Proposed resolution:
This wording is relative to N4830.
Modify 25.3.2 [range.access.begin] as follows:
-1- The name
ranges::begin
denotes a customization point object (16.3.3.3.5 [customization.point.object]). The expressionranges::begin(E)
for some subexpressionE
is expression-equivalent to:(1.1) —
E + 0
ifE
is an lvalue of array type (6.8.4 [basic.compound]).(1.2) — Otherwise, if
E
is an lvalue,decay-copy(E.begin())
if it is a valid expression and its typeI
modelsinput_or_output_iterator
.(1.3) — Otherwise,
decay-copy(begin(E))
if it is a valid expression and its typeI
modelsinput_or_output_iterator
with overload resolution performed in a context that includes the declarations:and does not include a declaration oftemplate<class T> void begin(T&&) = delete; template<class T> void begin(initializer_list<T>&&) = delete;ranges::begin
.[…]
Modify 25.3.3 [range.access.end] as follows:
-1- The name
ranges::end
denotes a customization point object (16.3.3.3.5 [customization.point.object]). The expressionranges::end(E)
for some subexpressionE
is expression-equivalent to:(1.1) —
E + extent_v<T>
ifE
is an lvalue of array type (6.8.4 [basic.compound])T
.(1.2) — Otherwise, if
E
is an lvalue,decay-copy(E.end())
if it is a valid expression and its typeS
modelssentinel_for<decltype(ranges::begin(E))>
(1.3) — Otherwise,
decay-copy(end(E))
if it is a valid expression and its typeS
modelssentinel_for<decltype(ranges::begin(E))>
with overload resolution performed in a context that includes the declarations:and does not include a declaration oftemplate<class T> void end(T&&) = delete; template<class T> void end(initializer_list<T>&&) = delete;ranges::end
.[…]
Modify 25.3.6 [range.access.rbegin] as follows:
-1- The name
ranges::rbegin
denotes a customization point object (16.3.3.3.5 [customization.point.object]). The expressionranges::rbegin(E)
for some subexpressionE
is expression-equivalent to:(1.1) — If
E
is an lvalue,decay-copy(E.rbegin())
if it is a valid expression and its typeI
modelsinput_or_output_iterator
.(1.2) — Otherwise,
decay-copy(rbegin(E))
if it is a valid expression and its typeI
modelsinput_or_output_iterator
with overload resolution performed in a context that includes the declarations:and does not include a declaration oftemplate<class T> void rbegin(T&&) = delete; template<class T> void rbegin(initializer_list<T>) = delete;ranges::rbegin
.[…]
Modify 25.3.7 [range.access.rend] as follows:
-1- The name
ranges::rend
denotes a customization point object (16.3.3.3.5 [customization.point.object]). The expressionranges::rend(E)
for some subexpressionE
is expression-equivalent to:(1.1) — If
E
is an lvalue,decay-copy(E.rend())
if it is a valid expression and its typeS
modelssentinel_for<decltype(ranges::rbegin(E))>(1.2) — Otherwise,
decay-copy(rend(E))
if it is a valid expression and its typeS
modelswith overload resolution performed in a context that includes the declarations:sentinel_for<decltype(ranges::rbegin(E))>and does not include a declaration oftemplate<class T> void rend(T&&) = delete; template<class T> void rend(initializer_list<T>) = delete;ranges::rend
.[…]