Topic: RFC: extended braced initializer deduction
Author: Ricardo Andrade <ricardofabianodeandrade@gmail.com>
Date: Thu, 10 Nov 2016 22:19:36 -0800 (PST)
Raw View
------=_Part_1122_437700912.1478845176942
Content-Type: multipart/alternative;
boundary="----=_Part_1123_1228528577.1478845176942"
------=_Part_1123_1228528577.1478845176942
Content-Type: text/plain; charset=UTF-8
A week ago, Johannes Schaub posted the following question on
[std-discussion]:
> Why is returning braced-initalizer-list from auto-function disallowed?
An he provided the following (slightly modified) example:
auto f() {
if(Foo g = fImpl())
return g;
return {}; // error here!
}
The discussion followed by others pointing that it happens because the
standard provides a simple rule where each `return` must be of the same
type.
To be more specific, Nicol Bolas mentioned:
> [dcl.spec.auto]/8
> If a function with a declared return type that contains a placeholder
type has multiple non-discarded return statements, the return type is
deduced for each such return statement. If the type deduced is not the same
in each deduction, the program is ill-formed.
I also understand such rule makes implementers' life easier by not having
to track all `return` to deduce `auto`.
Others pointed out supporting such construction would be beneficial by
bringing consistency to the language and by simplifying things on users'
side.
Patrice Roy then offered another example where a deduced braced-initializer would
be interesting:
auto maybe_I_guess(int n) {
return n < 0? optional<int>{ n } : {}; // meaning optional<int>{}?
}
I found myself in that position a few times:
// ...
auto list_or_empy = value ? list_values() : decltype(list_values()){}; //
violating DRY, I wish {} were sufficient.
// ...
takes_init_list(with_values ? { 1, 2, 3, 4 } : {}); // error, should it
deduce to initilizer_list<int>?
// ...
std::vector<int> get_results();
takes_vector(with_results ? get_results() : { 1, 2, 3, 4 }); // error,
should it deduce to vector<int>?
I haven't seem any further discussion on that topic since then, but I
believe relaxing such constraints would be beneficial.
So, I'd like to propose a few new rules for deducing braced-initializer in
those contexts (please forgive me for the lack of the standardese, using
"layman terms" here):
- When a braced-initializer appears as the second term of a ternary
operator, it is deduced as the constructor of the first term.
The first term must not be a braced-initializer.
- When both terms of ternary operation contain braced-initializers, they
are both deduced to std::initializer_list and there must be agreement on
the underlying type.
The second term can be empty braces, but not the first.
- When one or more braced-initializers appear in a function declared with
auto return type, if at least one return statement has type, all
braced-initializers are deduced to be of that type.
The first return statement must not be a braced-initializer.
- When all return statements in a function declared with auto return type
are braced-initializer, they're all deduced as std::initializer_list and
there must be agreement on the underlying type.
The first return statements must not be empty braces.
Maybe we could go without forbidding a braced-initializer as the first
term/return, but going with a conservative approach initially.
On the original post on [std-discussion], Nicol Bolas voiced that a change
in that direction would cause confusion.
However, the same is already possible in functions with defined return
types:
std::initializer_list<int> f() {
if (true) {
return {};
}
if (false) {
return {1,2};
}
return {1,2,3};
}
If I'm missing an important piece which would prevent this proposal from
working, please point me to the standard.
Also, if anyone sees other contexts where similar rules as the proposed
here could be used, I'd love to hear that too.
P.S.: Johannes and Patrice if you're already working in something similar,
my apologies.
Regards,
Ricardo Andrade
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/47a296e1-7f64-48bc-b74c-38771fa3e145%40isocpp.org.
------=_Part_1123_1228528577.1478845176942
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>A week ago, Johannes Schaub posted the following ques=
tion on [std-discussion]:<br></div><div>> Why is returning braced-inital=
izer-list from auto-function disallowed?</div><div><br></div><div>An he pro=
vided the following (slightly modified) example:</div><div><span style=3D"f=
ont-family: arial, sans-serif; font-size: 12.8px;">auto f() {</span><br sty=
le=3D"font-family: arial, sans-serif; font-size: 12.8px;"><span style=3D"fo=
nt-family: arial, sans-serif; font-size: 12.8px;">=C2=A0 =C2=A0if(Foo g =3D=
fImpl())</span><br style=3D"font-family: arial, sans-serif; font-size: 12.=
8px;"><span style=3D"font-family: arial, sans-serif; font-size: 12.8px;">=
=C2=A0 =C2=A0 =C2=A0 return g;</span><br style=3D"font-family: arial, sans-=
serif; font-size: 12.8px;"><span style=3D"font-family: arial, sans-serif; f=
ont-size: 12.8px;">=C2=A0 =C2=A0return {}; // error here!</span><br style=
=3D"font-family: arial, sans-serif; font-size: 12.8px;"><span style=3D"font=
-family: arial, sans-serif; font-size: 12.8px;">}</span><br></div><div><spa=
n style=3D"font-family: arial, sans-serif; font-size: 12.8px;"><br></span><=
/div><div><span style=3D"font-family: arial, sans-serif; font-size: 12.8px;=
">The discussion followed by others pointing that it happens because the st=
andard provides a simple rule where each `return` must be of the same type.=
</span></div><div><font face=3D"arial, sans-serif"><span style=3D"font-size=
: 12.8px;">To be more specific, Nicol Bolas mentioned:</span></font></div><=
div><span style=3D"font-family: arial, sans-serif; font-size: 12.8px;">>=
[dcl.spec.auto]/8</span><br style=3D"font-family: arial, sans-serif; font-=
size: 12.8px;"><span style=3D"font-family: arial, sans-serif; font-size: 12=
..8px;">> If a function with a declared return type that contains a place=
holder type has multiple non-discarded return statements, the return type i=
s deduced for each such return statement. If the type deduced is not the sa=
me in each deduction, the program is ill-formed.</span><font face=3D"arial,=
sans-serif"><span style=3D"font-size: 12.8px;"><br></span></font></div><di=
v><br></div><div><font face=3D"arial, sans-serif"><span style=3D"font-size:=
12.8px;">I also understand such rule makes implementers'=C2=A0life=C2=
=A0easier by not having to track all `return` to deduce `auto`.</span></fon=
t></div><div><font face=3D"arial, sans-serif"><span style=3D"font-size: 12.=
8px;">Others pointed out supporting such construction would be beneficial b=
y bringing consistency to the language and by simplifying things on users&#=
39; side.</span></font></div><div><font face=3D"arial, sans-serif"><span st=
yle=3D"font-size: 12.8px;"><br></span></font></div><div><font face=3D"arial=
, sans-serif"><span style=3D"font-size: 12.8px;">Patrice Roy then offered a=
nother=C2=A0</span></font><span style=3D"font-size: 12.8px; font-family: ar=
ial, sans-serif;">example where a deduced braced-initializer</span><span st=
yle=3D"font-size: 12.8px; font-family: arial, sans-serif;">=C2=A0would be i=
nteresting:</span></div><div><span style=3D"font-family: arial, sans-serif;=
font-size: 12.8px;">auto maybe_I_guess(int n) {</span><br style=3D"font-fa=
mily: arial, sans-serif; font-size: 12.8px;"><span style=3D"font-family: ar=
ial, sans-serif; font-size: 12.8px;">=C2=A0=C2=A0 return n < 0? optional=
<int>{ n } : {}; // meaning=C2=A0</span><span style=3D"font-family: a=
rial, sans-serif; font-size: 12.8px;">optional<int>{}?</span><br styl=
e=3D"font-family: arial, sans-serif; font-size: 12.8px;"><span style=3D"fon=
t-family: arial, sans-serif; font-size: 12.8px;">}</span><font face=3D"aria=
l, sans-serif"><span style=3D"font-size: 12.8px;"><br></span></font></div><=
div><span style=3D"font-family: arial, sans-serif; font-size: 12.8px;"><br>=
</span></div><div><font face=3D"arial, sans-serif"><span style=3D"font-size=
: 12.8px;">I found myself in that position a few times:</span></font></div>=
<div><span style=3D"font-size: 12.8px; font-family: arial, sans-serif;">// =
....</span></div><div><span style=3D"font-size: 12.8px; font-family: arial, =
sans-serif;">auto list_or_empy =3D value ? list_values() : decltype(list_va=
lues()){}; // violating DRY, I wish {} were sufficient.</span><br></div><di=
v>// ...</div><div>takes_init_list(with_values ? { 1, 2, 3, 4 } : {}); // e=
rror, should it deduce to initilizer_list<int>?<br></div><div>// ...<=
/div><div>std::vector<int> get_results();<br></div><div>takes_vector(=
with_results ? get_results() : { 1, 2, 3, 4 }); // error, should it deduce =
to vector<int>?</div><div><br></div><div>I haven't seem any furth=
er discussion on that topic since then, but I believe relaxing such constra=
ints would be beneficial.</div><div><br></div><div>So, I'd like to prop=
ose a few new rules for deducing braced-initializer in those contexts (plea=
se forgive me for the lack of the standardese, using "layman terms&quo=
t; here):</div><div>- When a braced-initializer appears as the second term =
of a ternary operator, it is deduced as the constructor of the first term.<=
/div><div>=C2=A0 The first term must not be a braced-initializer.</div><div=
>- When both terms of ternary operation contain braced-initializers, they a=
re both deduced to std::initializer_list and there must be agreement on the=
underlying=C2=A0type.</div><div>=C2=A0 The second term can be empty braces=
, but not the first.</div><div>- When one or more braced-initializers appea=
r in a function declared with auto return type, if at least one return stat=
ement has type, all braced-initializers are deduced to be of that type.</di=
v><div>=C2=A0 The first return statement must not be a braced-initializer.<=
/div><div>- When all return statements in a function declared with auto ret=
urn type are braced-initializer, they're all deduced as std::initialize=
r_list and there must be agreement on the underlying type.</div><div>=C2=A0=
The first return statements must not be empty braces.</div><div><br></div>=
<div>Maybe we could go without forbidding a braced-initializer as the first=
term/return, but going with a conservative approach initially.</div><div><=
br></div><div>On the original post on [std-discussion], Nicol Bolas voiced =
that a change in that direction would cause confusion.</div><div>However, t=
he same is already possible in functions with defined return types:</div><d=
iv><div>std::initializer_list<int> f() {</div><div>=C2=A0 =C2=A0 if (=
true) {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 return {};</div><div>=C2=A0 =
=C2=A0 }</div><div>=C2=A0 =C2=A0 if (false) {</div><div>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 return {1,2};</div><div>=C2=A0 =C2=A0 }</div><div>=C2=A0 =C2=A0 =
return {1,2,3};</div><div>}</div></div><div><br></div><div>If I'm missi=
ng an important piece which would prevent this proposal from working, pleas=
e point me to the standard.</div><div>Also, if anyone sees other contexts w=
here similar rules as the proposed here could be used, I'd love to hear=
that too.</div><div><br></div><div>P.S.: Johannes and Patrice if you'r=
e already working in something similar, my apologies.<br></div><div><br></d=
iv><div>Regards,</div><div>Ricardo Andrade</div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/47a296e1-7f64-48bc-b74c-38771fa3e145%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/47a296e1-7f64-48bc-b74c-38771fa3e145=
%40isocpp.org</a>.<br />
------=_Part_1123_1228528577.1478845176942--
------=_Part_1122_437700912.1478845176942--
.