Topic: RFC: Towards More Uniform Initialization proposal
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sun, 30 Dec 2012 13:49:21 -0800 (PST)
Raw View
------=_Part_337_15959070.1356904161500
Content-Type: multipart/alternative;
boundary="----=_Part_338_23522779.1356904161500"
------=_Part_338_23522779.1356904161500
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
What follows is a draft of a proposal for adding new rules for uniform=20
initialization syntax. It covers what it wants pretty well, so I'll let it=
=20
speak for itself.
Introduction
Braced-init-lists were originally used in object initialization with=20
aggregate initialization. In the development of C++11, the idea was=20
extended to include non-aggregate types through the use of a special=20
initializer_list type.
This idea was ultimately extended into what became known as uniform=20
initialization: one could initially any type via the use of a=20
braced-init-list. Doing so provides a number of advantages, among them is=
=20
uniform initialization behavior and the elimination of the most vexing=20
parse. In a perfect world, we would always use uniform initialization and=
=20
never use direct constructor syntax.
However, despite being called =93uniform initialization,=94 it cannot be=20
uniformly used everywhere, due to a critical flaw that prevents its use=20
towards these ends. This proposal intends to correct this flaw, thus=20
allowing it to be used in all possible cases of object construction, while=
=20
having well-defined results.
Motivation and Scope
The flaw in uniform initialization is quite simple to see in the standard=
=20
library. The std::vector type has an explicit constructor which takes a=20
single std::vector::size_type, which is an integral type. std::vector also=
=20
has a constructor that takes an initializer_list<T>.
For most types, these constructors can coexist with uniform initialization=
=20
quite reasonably. For example:
std::vector<A> v1{20};
std::vector<A> v2{A{}};
std::vector<A> v3{A{}, A{}, A{}};
In this example, v1 is an array of 20 value-constructed values. v2 is an=20
array of 1 value-constructed element. v3 is an array of 3 value-constructed=
=20
elements.
This is all well and good, until we do this:
std::vector<int> v1{20};
std::vector<int> v2{int{}};
std::vector<int> v3{int{}, int{}, int{}};
v2 and v3 retain their old meaning. But v1 is now very different. It is an=
=20
array containing a single element, the number 20. Why?
Because uniform initialization syntax always prefers initializer list=20
constructors if one is available that would fit the braced-init-list. This=
=20
is a consequence of uniform initialization syntax using the same syntax as=
=20
initializer lists: the braced-init-list. And since=20
std::vector<int>::vector(std::initializer_list<int>) matches the=20
braced-init-list ({20}), it will be preferred over=20
std::vector<int>::vector(std::vector<int>::size_type)
This is a problem because there is *no way* to get at the size_typeconstruc=
tor via uniform initialization. There is no syntax that we can=20
employ which will cause the conflicting initializer_list constructor to be=
=20
ignored or to do anything else that would allow us to get at a different=20
set of constructors.
Now, this may seem like a rather unimportant issue. After all, if I know=20
that I have to use constructor initialization with vector<int>, then I can=
=20
simply do that. But consider code that is generic on the vector's type:
template<typename T>
std::vector<T> MakeVector()
{
return std::vector<T>{20};
}
By all rights, this code should always do the same thing: return a vectorco=
ntaining 20 value-initialized elements. But it does not.=20
MakeVector<int>() will return a vector containing exactly one element.
This is of much greater concern when dealing with more intricate templates.=
=20
Consider the following trivial template function:
template<typename T>
T Process()
{
T t{};
//do stuff with t;
return T{t};
}
This function creates a temporary, does some processing, and returns a copy=
=20
of it. This function requires that T be DefaultConstructible and=20
CopyConstructible, in addition to whatever =93do stuff with t=94 requires.
The problem is the last line. This line *may* violate the concept=20
constraint. Why? Because there is no guarantee that T does *not* have an=20
initializer_list constructor that can match with a T. For an example of=20
such a class, consider std::vector<std::function<void()>> as our T.
The problem is that std::function has a non-explicit constructor that can=
=20
take *any* type that is CopyConstructible. And std::vector<std::function>is=
CopyConstructible. Therefore, this will call the initializer_list=20
constructor. But the template function should not be calling the=20
initializer list constructor; it's not part of the allowed interface to T.=
=20
Therefore, Process violates the concept constraint, through no fault on the=
=20
user's part.
What this means is that you cannot use uniform initialization in generic=20
code where the exact type of the object being constructed is derived from a=
=20
template parameter. This is because there is no way for the user to=20
explicitly choose which constructors to call.
Design Overview
The idea is quite simple. We will divide braced-init-list up into two=20
variation: list-braced-init-list and constr-braced-init-list. Most of the=
=20
text will remain the exact same, as they have almost identical behavior.
The difference is that 13.3.1.7's list initialization overload resolution=
=20
rules will behave differently. list-braced-init-list initialization will=20
work exactly as it does. constr-braced-init-list will work opposite to the=
=20
current way. That is, it will check non-initializer_list constructors=20
first, then go to the initializer_list ones if no matching constructors are=
=20
found. All other uses will work identically; you can use these for=20
aggregate initialization and so forth just as before.
The big issue is how constr-braced-init-lists are defined in the grammar.=
=20
It should look like this:
{^ ... }
The =93{=94 token followed by the =93^=94 token is what distinguishes the=
=20
constr-braced-init-list from a list-braced-init-list.
Note
I have no particular love for the use of =93^=94 here. My reasons for its=
=20
selection are listed in the Grammar section of the Design Discussions=20
segment of the document.
Impact on the Standard
Depending on how we want to handle the wording, we may need a new set of =
=93
list-initialization=94 types. 13.3.1.7 never mentions braced-init-list; it=
=20
only operates in terms of list-initialization, which stems from a specific=
=20
use of braced-init-list. We could have it say something like =93if the=20
braced-init-list that issues this constructor is a list-braced-init-list,=
=20
then ...=94 Or we could provide different forms of =93list-initialization.=
=94
It should cause zero backwards compatibility problems.=20
list-braced-init-lists should have the same behavior as before. Also, see=
=20
the Design Decisions section, the Grammar part.
Design Decisions
Bikeshedding
Finding the right grammar for this will likely be the biggest stumbling=20
point. I would say that the most important metrics for a good piece of=20
grammar are:
-=20
=20
Backwards compatibility. Whatever grammar we use, it should be something=
=20
that would have been illegal in C++11, no matter what literals,=20
identifiers, and tokens come after it.
-=20
=20
Brevity. It should be used a lot, so it shouldn't take up a lot of space=
..
=20
This leaves few candidates. Here are some potential alternatives:
{ explicit ... } //Keyword makes it clear what's going on.
{, ...} //Comma at the start would normally be illegal.
{| ...}
We could in theory use any operator that only has a binary operation mode.=
=20
The use of =93^=94 could interfere with C++/CX and other similar library=20
extensions, so =93|=94 or some other operator would be acceptable.
The operator should probably be within the braces, as this makes it more=20
explicit which is being used.
Library vs Language
Originally, I considered a library-based solution to the issue. This would=
=20
have required adding a special opaque type taken as a parameter to various=
=20
calls. Since the opaque type is different from other types, it would=20
prevent the braced-init-list from binding to an initializer_listconstructor=
, thus disambiguating the call.
This is problematic for two reasons. First, it adds some complexity to=20
various container classes, as they have to prevent the user from using the=
=20
opaque type as the member or allocator types. But the primary reason that=
=20
this is not a good solution is because it only solves the problem for the=
=20
standard library.
We should not ask every user who writes an initializer_list constructor to=
=20
go though and add a suffix parameter to various functions. This is a=20
problem introduced by the language, and it is best solved in the language.
Alternate Designs
constr-braced-init-list, in the current design, is intended to work exactly=
=20
like braced-init-list except for which constructors hide which. That is, it=
=20
could still access initializer_list constructors.
We don't have to do that. There are two other alternatives. We could make=
=20
constr-braced-init-list *never* use initializer list constructors. This=20
would be more uniform in some respects:
vector<int> v1{20}; //Creates an array of 1 item.
vector<int> v2{^20}; //Creates an array of 20 items.
vector<int> v3{20, 30, 40}; //Creates an array of 3 items.
vector<int> v4{^20, 30, 40}; //Creates an array of 3 items.
The oddball here is v2, which calls a constructor. It would be more uniform=
=20
to require this:
vector<int> v1{{^20}}; //Creates an array of 1 item.
vector<int> v2{^20}; //Creates an array of 20 items.
vector<int> v1{^{20, 30, 40}}; //Creates an array of 3 items.
vector<int> v1{^20, 30, 40}; //Compiler error; no appropriate constructor t=
o call.
The question then becomes whether constr-braced-init-list should retain the=
=20
*other* similarities to regular braced-init-lists. Should this be allowed:
array<int, 3> a1{^10, 20, 30};
That is, do we want to forbid constr-braced-init-lists from initializing=20
with anything other than non-initializer_list constructors?
I would say no, and here is why.
Currently, std::allocator_traits::construct is defined in terms of calling =
new(/*stuff*/)=20
T(std::forward<Args>(args)...). That will call constructors, but it will *
only* call constructors. If we have a simple struct that could use=20
aggregate initialization, we cannot use, for example, emplace on it:
struct Agg {int first, int second};
std::vector<Agg> ag{{10, 20}, {20, 30}, {30, 40}}; //Aggregate initializati=
on is OK here.
ag.emplace_back(10, 20); //Error: no aggregate initialization is possible.
There is no reason why we shouldn't be able to do this. To have this, we=20
would need to be able to have std::allocator_traits::construct use uniform=
=20
initialization syntax: new(/*stuff*/) T{std::forward<Args>(args)...}.=20
However, this can hide constructors; vector<vector<int>>::emplace_back(10)w=
ill add a vector containing one element. This will break existing=20
applications, not to mention make it completely impossible to access the=20
hidden constructors via emplace.
By defining constr-braced-init-lists as being exactly equal to=20
braced-init-list except for which constructors it prefers, it makes it=20
possible to redefine std::allocator_traits::construct in terms of=20
constr-braced-init-lists. This now means that the emplace calls can access=
=20
aggregate initialization if the type supports it.
Change the Definition
There was an alternate design to resolve the issue. Simply declare that non=
-
initializer_list constructors have priority, instead of the other way=20
around. This would make these completely unambiguous:
std::vector<int> v1{20};
std::vector<int> v2{{20}};
v1 is using the size_type constructor. v2 is clearly calling a=20
single-argument constructor using a braced-init-list.
The obvious problem with this is that it is a breaking change and a *silent=
*one at that.
Even worse, it doesn't look uniform:
std::array<int, 6> a1 =3D {1, 2, 3, 4, 5, 6}; //Brace elision removes the e=
xtra pair.
std::vector<int> v1 =3D {1, 2, 3, 4, 5, 6}; //Brace "elision" possible.
std::array<int, 1> a2 =3D {1}; //Brace elision still works.
std::vector<int> v2 =3D {1}; //Brace "elision" no longer possible due to =
conflict. Does the wrong thing.
Honestly, this would be the preferable solution, if it were not a breaking=
=20
change. But it is, so we probably shouldn't do it.
--=20
------=_Part_338_23522779.1356904161500
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
What follows is a draft of a proposal for adding new rules for uniform init=
ialization syntax. It covers what it wants pretty well, so I'll let it spea=
k for itself.<br><br><div class=3D"section" title=3D"Introduction"><div cla=
ss=3D"titlepage"><div><div><h2 class=3D"title" style=3D"clear: both"><a nam=
e=3D"d0e6"></a>Introduction</h2></div></div></div><p>Braced-init-lists were=
originally used in object initialization with aggregate
initialization. In the development of C++11, the idea was exten=
ded to include
non-aggregate types through the use of a special <span class=3D=
"type">initializer_list</span>
type.</p><p>This idea was ultimately extended into what became =
known as uniform initialization:
one could initially any type via the use of a braced-init-list.=
Doing so provides a
number of advantages, among them is uniform initialization beha=
vior and the elimination
of the most vexing parse. In a perfect world, we would always u=
se uniform initialization
and never use direct constructor syntax.</p><p>However, despite=
being called <span class=3D"quote">=93<span class=3D"quote">uniform initia=
lization,</span>=94</span> it cannot be
uniformly used everywhere, due to a critical flaw that prevents=
its use towards these
ends. This proposal intends to correct this flaw, thus allowing=
it to be used in all
possible cases of object construction, while having well-define=
d results.</p></div><div class=3D"section" title=3D"Motivation and Scope"><=
div class=3D"titlepage"><div><div><h2 class=3D"title" style=3D"clear: both"=
><a name=3D"d0e21"></a>Motivation and Scope</h2></div></div></div><p>The fl=
aw in uniform initialization is quite simple to see in the standard library=
.. The
<span class=3D"type">std::vector</span> type has an explici=
t constructor which takes a single
<span class=3D"type">std::vector::size_type</span>, which i=
s an integral type.
<span class=3D"type">std::vector</span> also has a construc=
tor that takes an
<span class=3D"type">initializer_list<T></span>.</p><=
p>For most types, these constructors can coexist with uniform initializatio=
n quite
reasonably. For example:</p><pre class=3D"programlisting">std::=
vector<A> v1{20};
std::vector<A> v2{A{}};
std::vector<A> v3{A{}, A{}, A{}};</pre><p>In this example, <code clas=
s=3D"varname">v1</code> is an array of 20 value-constructed values.
<code class=3D"varname">v2</code> is an array of 1 value-co=
nstructed element.
<code class=3D"varname">v3</code> is an array of 3 value-co=
nstructed elements.</p><p>This is all well and good, until we do this:</p><=
pre class=3D"programlisting">std::vector<int> v1{20};
std::vector<int> v2{int{}};
std::vector<int> v3{int{}, int{}, int{}};</pre><p><code class=3D"varn=
ame">v2</code> and <code class=3D"varname">v3</code> retain their old meani=
ng. But
<code class=3D"varname">v1</code> is now very different. It=
is an array containing a single
element, the number 20. Why?</p><p>Because uniform initializati=
on syntax always prefers initializer list constructors if
one is available that would fit the braced-init-list. This is a=
consequence of uniform
initialization syntax using the same syntax as initializer list=
s: the braced-init-list.
And since
<code class=3D"function">std::vector<int>::vector(std=
::initializer_list<int>)</code>
matches the braced-init-list (<code class=3D"literal">{20}</cod=
e>), it will be preferred over
<code class=3D"function">std::vector<int>::vector(std=
::vector<int>::size_type)</code></p><p>This is a problem because ther=
e is <span class=3D"emphasis"><em>no way</em></span> to get at the
<span class=3D"type">size_type</span> constructor via unifo=
rm initialization. There is no syntax
that we can employ which will cause the conflicting <span class=
=3D"type">initializer_list</span>
constructor to be ignored or to do anything else that would all=
ow us to get at a
different set of constructors.</p><p>Now, this may seem like a =
rather unimportant issue. After all, if I know that I have
to use constructor initialization with <span class=3D"type">vec=
tor<int></span>, then I can simply do
that. But consider code that is generic on the <span class=3D"t=
ype">vector</span>'s type:</p><pre class=3D"programlisting">template<typ=
ename T>
std::vector<T> MakeVector()
{
return std::vector<T>{20};
}</pre><p>By all rights, this code should always do the same thing: return =
a <span class=3D"type">vector</span>
containing 20 value-initialized elements. But it does not.
<code class=3D"function">MakeVector<int>()</code> wil=
l return a <span class=3D"type">vector</span>
containing exactly one element.</p><p>This is of much greater c=
oncern when dealing with more intricate templates. Consider
the following trivial template function:</p><pre class=3D"progr=
amlisting">template<typename T>
T Process()
{
T t{};
//do stuff with t;
return T{t};
}</pre><p>This function creates a temporary, does some processing, and retu=
rns a copy of it.
This function requires that <span class=3D"type">T</span> be De=
faultConstructible and
CopyConstructible, in addition to whatever <span class=3D"quote=
">=93<span class=3D"quote">do stuff with t</span>=94</span>
requires.</p><p>The problem is the last line. This line <span c=
lass=3D"emphasis"><em>may</em></span> violate the concept
constraint. Why? Because there is no guarantee that <span class=
=3D"type">T</span> does
<span class=3D"emphasis"><em>not</em></span> have an <span =
class=3D"type">initializer_list</span> constructor that can
match with a <span class=3D"type">T</span>. For an example of s=
uch a class, consider
<span class=3D"type">std::vector<std::function<void()=
>></span> as our <span class=3D"type">T</span>.</p><p>The problem is =
that <span class=3D"type">std::function</span> has a non-explicit construct=
or that can
take <span class=3D"emphasis"><em>any</em></span> type that is =
CopyConstructible. And
<span class=3D"type">std::vector<std::function></span=
> is CopyConstructible. Therefore, this
will call the initializer_list constructor. But the template fu=
nction should not be
calling the initializer list constructor; it's not part of the =
allowed interface to T.
Therefore, <code class=3D"function">Process</code> violates the=
concept constraint, through no
fault on the user's part.</p><p>What this means is that you can=
not use uniform initialization in generic code where
the exact type of the object being constructed is derived from =
a template parameter.
This is because there is no way for the user to explicitly choo=
se which constructors to
call.</p></div><div class=3D"section" title=3D"Design Overview"=
><div class=3D"titlepage"><div><div><h2 class=3D"title" style=3D"clear: bot=
h"><a name=3D"d0e160"></a>Design Overview</h2></div></div></div><p>The idea=
is quite simple. We will divide braced-init-list up into two variation:
list-braced-init-list and constr-braced-init-list. Most of the =
text will remain the
exact same, as they have almost identical behavior.</p><p>The d=
ifference is that 13.3.1.7's list initialization overload resolution rules =
will
behave differently. list-braced-init-list initialization will w=
ork exactly as it does.
constr-braced-init-list will work opposite to the current way. =
That is, it will check
non-initializer_list constructors first, then go to the initial=
izer_list ones if no
matching constructors are found. All other uses will work ident=
ically; you can use these
for aggregate initialization and so forth just as before.</p><p=
>The big issue is how constr-braced-init-lists are defined in the grammar. =
It should
look like this:</p><pre class=3D"programlisting">{^ ... }</pre>=
<p>The <span class=3D"quote">=93<span class=3D"quote">{</span>=94</span> to=
ken followed by the <span class=3D"quote">=93<span class=3D"quote">^</span>=
=94</span> token is what
distinguishes the constr-braced-init-list from a list-braced-in=
it-list.</p><div class=3D"note" title=3D"Note" style=3D"margin-left: 0.5in;=
margin-right: 0.5in;"><h3 class=3D"title">Note</h3><p>I have no particular=
love for the use of <span class=3D"quote">=93<span class=3D"quote">^</span=
>=94</span> here. My reasons for its
selection are listed in the Grammar section of the Design D=
iscussions segment of the
document.</p></div></div><div class=3D"section" title=3D"Im=
pact on the Standard"><div class=3D"titlepage"><div><div><h2 class=3D"title=
" style=3D"clear: both"><a name=3D"d0e185"></a>Impact on the Standard</h2><=
/div></div></div><p>Depending on how we want to handle the wording, we may =
need a new set of
<span class=3D"quote">=93<span class=3D"quote">list-initial=
ization</span>=94</span> types. 13.3.1.7 never mentions braced-init-list;
it only operates in terms of list-initialization, which stems f=
rom a specific use of
braced-init-list. We could have it say something like <span cla=
ss=3D"quote">=93<span class=3D"quote">if the braced-init-list
that issues this constructor is a list-braced-init-list, th=
en ...</span>=94</span> Or we
could provide different forms of <span class=3D"quote">=93<span=
class=3D"quote">list-initialization.</span>=94</span></p><p>It should caus=
e zero backwards compatibility problems. list-braced-init-lists should
have the same behavior as before. Also, see the Design Decision=
s section, the Grammar
part.</p></div><div class=3D"section" title=3D"Design Decisions=
"><div class=3D"titlepage"><div><div><h2 class=3D"title" style=3D"clear: bo=
th"><a name=3D"d0e200"></a>Design Decisions</h2></div></div></div><div clas=
s=3D"section" title=3D"Bikeshedding"><div class=3D"titlepage"><div><div><h3=
class=3D"title"><a name=3D"d0e203"></a>Bikeshedding</h3></div></div></div>=
<p>Finding the right grammar for this will likely be the biggest stumbling =
point. I
would say that the most important metrics for a good piece =
of grammar are:</p><div class=3D"itemizedlist"><ul class=3D"itemizedlist" t=
ype=3D"disc"><li class=3D"listitem"><p>Backwards compatibility. Whatever gr=
ammar we use, it should be something
that would have been illegal in C++11, no matter wh=
at literals, identifiers,
and tokens come after it.</p></li><li class=3D"list=
item"><p>Brevity. It should be used a lot, so it shouldn't take up a lot of
space.</p></li></ul></div><p>This leaves few candid=
ates. Here are some potential alternatives:</p><pre class=3D"programlisting=
">{ explicit ... } //Keyword makes it clear what's going on.
{, ...} //Comma at the start would normally be illegal.
{| ...}
</pre><p>We could in theory use any operator that only has a binary operati=
on mode. The use
of <span class=3D"quote">=93<span class=3D"quote">^</span>=
=94</span> could interfere with C++/CX and other similar library
extensions, so <span class=3D"quote">=93<span class=3D"quot=
e">|</span>=94</span> or some other operator would be acceptable.</p><p>The=
operator should probably be within the braces, as this makes it more expli=
cit
which is being used.</p></div><div class=3D"section" title=
=3D"Library vs Language"><div class=3D"titlepage"><div><div><h3 class=3D"ti=
tle"><a name=3D"d0e229"></a>Library vs Language</h3></div></div></div><p>Or=
iginally, I considered a library-based solution to the issue. This would ha=
ve
required adding a special opaque type taken as a parameter =
to various calls. Since
the opaque type is different from other types, it would pre=
vent the braced-init-list
from binding to an <span class=3D"type">initializer_list</s=
pan> constructor, thus disambiguating
the call.</p><p>This is problematic for two reasons. First,=
it adds some complexity to various
container classes, as they have to prevent the user from us=
ing the opaque type as
the member or allocator types. But the primary reason that =
this is not a good
solution is because it only solves the problem for the stan=
dard library.</p><p>We should not ask every user who writes an <span class=
=3D"type">initializer_list</span>
constructor to go though and add a suffix parameter to vari=
ous functions. This is a
problem introduced by the language, and it is best solved i=
n the language.</p></div><div class=3D"section" title=3D"Alternate Designs"=
><div class=3D"titlepage"><div><div><h3 class=3D"title"><a name=3D"d0e244">=
</a>Alternate Designs</h3></div></div></div><p>constr-braced-init-list, in =
the current design, is intended to work exactly like
braced-init-list except for which constructors hide which. =
That is, it could still
access <span class=3D"type">initializer_list</span> constru=
ctors.</p><p>We don't have to do that. There are two other alternatives. We=
could make
constr-braced-init-list <span class=3D"emphasis"><em>never<=
/em></span> use initializer list
constructors. This would be more uniform in some respects:<=
/p><pre class=3D"programlisting">vector<int> v1{20}; //Creates an arr=
ay of 1 item.
vector<int> v2{^20}; //Creates an array of 20 items.
vector<int> v3{20, 30, 40}; //Creates an array of 3 items.
vector<int> v4{^20, 30, 40}; //Creates an array of 3 items.</pre><p>T=
he oddball here is <code class=3D"varname">v2</code>, which calls a constru=
ctor. It would be
more uniform to require this:</p><pre class=3D"programlisti=
ng">vector<int> v1{{^20}}; //Creates an array of 1 item.
vector<int> v2{^20}; //Creates an array of 20 items.
vector<int> v1{^{20, 30, 40}}; //Creates an array of 3 items.
vector<int> v1{^20, 30, 40}; //Compiler error; no appropriate constru=
ctor to call.</pre><p>The question then becomes whether constr-braced-init-=
list should retain the
<span class=3D"emphasis"><em>other</em></span> similari=
ties to regular braced-init-lists. Should
this be allowed:</p><pre class=3D"programlisting">array<=
int, 3> a1{^10, 20, 30};</pre><p>That is, do we want to forbid constr-br=
aced-init-lists from initializing with
anything other than non-initializer_list constructors?</p><=
p>I would say no, and here is why.</p><p>Currently, <code class=3D"function=
">std::allocator_traits::construct</code> is defined in
terms of calling <code class=3D"literal">new(/*stuff*/)
T(std::forward<Args>(args)...)</code>. That will call=
constructors, but it
will <span class=3D"emphasis"><em>only</em></span> call con=
structors. If we have a simple struct that
could use aggregate initialization, we cannot use, for exam=
ple,
<code class=3D"function">emplace</code> on it:</p><pre =
class=3D"programlisting">struct Agg {int first, int second};
std::vector<Agg> ag{{10, 20}, {20, 30}, {30, 40}}; //Aggregate initia=
lization is OK here.
ag.emplace_back(10, 20); //Error: no aggregate initialization is possible.<=
/pre><p>There is no reason why we shouldn't be able to do this. To have thi=
s, we would
need to be able to have std::allocator_traits::construct us=
e uniform initialization
syntax: <code class=3D"literal">new(/*stuff*/) T{std::forwa=
rd<Args>(args)...}</code>.
However, this can hide constructors;
<code class=3D"literal">vector<vector<int>>=
::emplace_back(10)</code> will add a vector
containing one element. This will break existing applicatio=
ns, not to mention make
it completely impossible to access the hidden constructors =
via
<code class=3D"function">emplace</code>.</p><p>By defin=
ing constr-braced-init-lists as being exactly equal to braced-init-list
except for which constructors it prefers, it makes it possi=
ble to redefine
<code class=3D"function">std::allocator_traits::constru=
ct</code> in terms of
<code class=3D"function">constr-braced-init-lists</code=
>. This now means that the
<code class=3D"function">emplace</code> calls can acces=
s aggregate initialization if the
type supports it.</p></div><div class=3D"section" title=3D"=
Change the Definition"><div class=3D"titlepage"><div><div><h3 class=3D"titl=
e"><a name=3D"d0e315"></a>Change the Definition</h3></div></div></div><p>Th=
ere was an alternate design to resolve the issue. Simply declare that
non-<span class=3D"type">initializer_list</span> constr=
uctors have priority, instead of the
other way around. This would make these completely unambigu=
ous:</p><pre class=3D"programlisting">std::vector<int> v1{20};
std::vector<int> v2{{20}};</pre><p><span class=3D"type">v1</span> is =
using the <span class=3D"type">size_type</span> constructor. <span class=3D=
"type">v2</span>
is clearly calling a single-argument constructor using a br=
aced-init-list.</p><p>The obvious problem with this is that it is a breakin=
g change and a
<span class=3D"emphasis"><em>silent</em></span> one at =
that.</p><p>Even worse, it doesn't look uniform:</p><pre class=3D"programli=
sting">std::array<int, 6> a1 =3D {1, 2, 3, 4, 5, 6}; //Brace elision =
removes the extra pair.
std::vector<int> v1 =3D {1, 2, 3, 4, 5, 6}; //Brace "elision" possibl=
e.
std::array<int, 1> a2 =3D {1}; //Brace elision still works.
std::vector<int> v2 =3D {1}; //Brace "elision" no longer possible d=
ue to conflict. Does the wrong thing.</pre><p>Honestly, this would be the p=
referable solution, if it were not a breaking change.
But it is, so we probably shouldn't do it.</p></div></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_338_23522779.1356904161500--
------=_Part_337_15959070.1356904161500
Content-Type: text/html; charset=US-ASCII;
name="Towards More Uniform Initialization.html"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="Towards More Uniform Initialization.html"
X-Attachment-Id: e8151474-a70e-4ccc-93ef-09717530b6ac
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Towards More Uniform Initialization</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="article" title="Towards More Uniform Initialization"><div class="titlepage"><div><div><h2 class="title"><a name="d0e3"></a>Towards More Uniform Initialization</h2></div></div><hr></div><div class="section" title="Introduction"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e6"></a>Introduction</h2></div></div></div><p>Braced-init-lists were originally used in object initialization with aggregate
initialization. In the development of C++11, the idea was extended to include
non-aggregate types through the use of a special <span class="type">initializer_list</span>
type.</p><p>This idea was ultimately extended into what became known as uniform initialization:
one could initially any type via the use of a braced-init-list. Doing so provides a
number of advantages, among them is uniform initialization behavior and the elimination
of the most vexing parse. In a perfect world, we would always use uniform initialization
and never use direct constructor syntax.</p><p>However, despite being called <span class="quote">“<span class="quote">uniform initialization,</span>”</span> it cannot be
uniformly used everywhere, due to a critical flaw that prevents its use towards these
ends. This proposal intends to correct this flaw, thus allowing it to be used in all
possible cases of object construction, while having well-defined results.</p></div><div class="section" title="Motivation and Scope"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e21"></a>Motivation and Scope</h2></div></div></div><p>The flaw in uniform initialization is quite simple to see in the standard library. The
<span class="type">std::vector</span> type has an explicit constructor which takes a single
<span class="type">std::vector::size_type</span>, which is an integral type.
<span class="type">std::vector</span> also has a constructor that takes an
<span class="type">initializer_list<T></span>.</p><p>For most types, these constructors can coexist with uniform initialization quite
reasonably. For example:</p><pre class="programlisting">std::vector<A> v1{20};
std::vector<A> v2{A{}};
std::vector<A> v3{A{}, A{}, A{}};</pre><p>In this example, <code class="varname">v1</code> is an array of 20 value-constructed values.
<code class="varname">v2</code> is an array of 1 value-constructed element.
<code class="varname">v3</code> is an array of 3 value-constructed elements.</p><p>This is all well and good, until we do this:</p><pre class="programlisting">std::vector<int> v1{20};
std::vector<int> v2{int{}};
std::vector<int> v3{int{}, int{}, int{}};</pre><p><code class="varname">v2</code> and <code class="varname">v3</code> retain their old meaning. But
<code class="varname">v1</code> is now very different. It is an array containing a single
element, the number 20. Why?</p><p>Because uniform initialization syntax always prefers initializer list constructors if
one is available that would fit the braced-init-list. This is a consequence of uniform
initialization syntax using the same syntax as initializer lists: the braced-init-list.
And since
<code class="function">std::vector<int>::vector(std::initializer_list<int>)</code>
matches the braced-init-list (<code class="literal">{20}</code>), it will be preferred over
<code class="function">std::vector<int>::vector(std::vector<int>::size_type)</code></p><p>This is a problem because there is <span class="emphasis"><em>no way</em></span> to get at the
<span class="type">size_type</span> constructor via uniform initialization. There is no syntax
that we can employ which will cause the conflicting <span class="type">initializer_list</span>
constructor to be ignored or to do anything else that would allow us to get at a
different set of constructors.</p><p>Now, this may seem like a rather unimportant issue. After all, if I know that I have
to use constructor initialization with <span class="type">vector<int></span>, then I can simply do
that. But consider code that is generic on the <span class="type">vector</span>'s type:</p><pre class="programlisting">template<typename T>
std::vector<T> MakeVector()
{
return std::vector<T>{20};
}</pre><p>By all rights, this code should always do the same thing: return a <span class="type">vector</span>
containing 20 value-initialized elements. But it does not.
<code class="function">MakeVector<int>()</code> will return a <span class="type">vector</span>
containing exactly one element.</p><p>This is of much greater concern when dealing with more intricate templates. Consider
the following trivial template function:</p><pre class="programlisting">template<typename T>
T Process()
{
T t{};
//do stuff with t;
return T{t};
}</pre><p>This function creates a temporary, does some processing, and returns a copy of it.
This function requires that <span class="type">T</span> be DefaultConstructible and
CopyConstructible, in addition to whatever <span class="quote">“<span class="quote">do stuff with t</span>”</span>
requires.</p><p>The problem is the last line. This line <span class="emphasis"><em>may</em></span> violate the concept
constraint. Why? Because there is no guarantee that <span class="type">T</span> does
<span class="emphasis"><em>not</em></span> have an <span class="type">initializer_list</span> constructor that can
match with a <span class="type">T</span>. For an example of such a class, consider
<span class="type">std::vector<std::function<void()>></span> as our <span class="type">T</span>.</p><p>The problem is that <span class="type">std::function</span> has a non-explicit constructor that can
take <span class="emphasis"><em>any</em></span> type that is CopyConstructible. And
<span class="type">std::vector<std::function></span> is CopyConstructible. Therefore, this
will call the initializer_list constructor. But the template function should not be
calling the initializer list constructor; it's not part of the allowed interface to T.
Therefore, <code class="function">Process</code> violates the concept constraint, through no
fault on the user's part.</p><p>What this means is that you cannot use uniform initialization in generic code where
the exact type of the object being constructed is derived from a template parameter.
This is because there is no way for the user to explicitly choose which constructors to
call.</p></div><div class="section" title="Design Overview"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e160"></a>Design Overview</h2></div></div></div><p>The idea is quite simple. We will divide braced-init-list up into two variation:
list-braced-init-list and constr-braced-init-list. Most of the text will remain the
exact same, as they have almost identical behavior.</p><p>The difference is that 13.3.1.7's list initialization overload resolution rules will
behave differently. list-braced-init-list initialization will work exactly as it does.
constr-braced-init-list will work opposite to the current way. That is, it will check
non-initializer_list constructors first, then go to the initializer_list ones if no
matching constructors are found. All other uses will work identically; you can use these
for aggregate initialization and so forth just as before.</p><p>The big issue is how constr-braced-init-lists are defined in the grammar. It should
look like this:</p><pre class="programlisting">{^ ... }</pre><p>The <span class="quote">“<span class="quote">{</span>”</span> token followed by the <span class="quote">“<span class="quote">^</span>”</span> token is what
distinguishes the constr-braced-init-list from a list-braced-init-list.</p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>I have no particular love for the use of <span class="quote">“<span class="quote">^</span>”</span> here. My reasons for its
selection are listed in the Grammar section of the Design Discussions segment of the
document.</p></div></div><div class="section" title="Impact on the Standard"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e185"></a>Impact on the Standard</h2></div></div></div><p>Depending on how we want to handle the wording, we may need a new set of
<span class="quote">“<span class="quote">list-initialization</span>”</span> types. 13.3.1.7 never mentions braced-init-list;
it only operates in terms of list-initialization, which stems from a specific use of
braced-init-list. We could have it say something like <span class="quote">“<span class="quote">if the braced-init-list
that issues this constructor is a list-braced-init-list, then ...</span>”</span> Or we
could provide different forms of <span class="quote">“<span class="quote">list-initialization.</span>”</span></p><p>It should cause zero backwards compatibility problems. list-braced-init-lists should
have the same behavior as before. Also, see the Design Decisions section, the Grammar
part.</p></div><div class="section" title="Design Decisions"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e200"></a>Design Decisions</h2></div></div></div><div class="section" title="Bikeshedding"><div class="titlepage"><div><div><h3 class="title"><a name="d0e203"></a>Bikeshedding</h3></div></div></div><p>Finding the right grammar for this will likely be the biggest stumbling point. I
would say that the most important metrics for a good piece of grammar are:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Backwards compatibility. Whatever grammar we use, it should be something
that would have been illegal in C++11, no matter what literals, identifiers,
and tokens come after it.</p></li><li class="listitem"><p>Brevity. It should be used a lot, so it shouldn't take up a lot of
space.</p></li></ul></div><p>This leaves few candidates. Here are some potential alternatives:</p><pre class="programlisting">{ explicit ... } //Keyword makes it clear what's going on.
{, ...} //Comma at the start would normally be illegal.
{| ...}
</pre><p>We could in theory use any operator that only has a binary operation mode. The use
of <span class="quote">“<span class="quote">^</span>”</span> could interfere with C++/CX and other similar library
extensions, so <span class="quote">“<span class="quote">|</span>”</span> or some other operator would be acceptable.</p><p>The operator should probably be within the braces, as this makes it more explicit
which is being used.</p></div><div class="section" title="Library vs Language"><div class="titlepage"><div><div><h3 class="title"><a name="d0e229"></a>Library vs Language</h3></div></div></div><p>Originally, I considered a library-based solution to the issue. This would have
required adding a special opaque type taken as a parameter to various calls. Since
the opaque type is different from other types, it would prevent the braced-init-list
from binding to an <span class="type">initializer_list</span> constructor, thus disambiguating
the call.</p><p>This is problematic for two reasons. First, it adds some complexity to various
container classes, as they have to prevent the user from using the opaque type as
the member or allocator types. But the primary reason that this is not a good
solution is because it only solves the problem for the standard library.</p><p>We should not ask every user who writes an <span class="type">initializer_list</span>
constructor to go though and add a suffix parameter to various functions. This is a
problem introduced by the language, and it is best solved in the language.</p></div><div class="section" title="Alternate Designs"><div class="titlepage"><div><div><h3 class="title"><a name="d0e244"></a>Alternate Designs</h3></div></div></div><p>constr-braced-init-list, in the current design, is intended to work exactly like
braced-init-list except for which constructors hide which. That is, it could still
access <span class="type">initializer_list</span> constructors.</p><p>We don't have to do that. There are two other alternatives. We could make
constr-braced-init-list <span class="emphasis"><em>never</em></span> use initializer list
constructors. This would be more uniform in some respects:</p><pre class="programlisting">vector<int> v1{20}; //Creates an array of 1 item.
vector<int> v2{^20}; //Creates an array of 20 items.
vector<int> v3{20, 30, 40}; //Creates an array of 3 items.
vector<int> v4{^20, 30, 40}; //Creates an array of 3 items.</pre><p>The oddball here is <code class="varname">v2</code>, which calls a constructor. It would be
more uniform to require this:</p><pre class="programlisting">vector<int> v1{{^20}}; //Creates an array of 1 item.
vector<int> v2{^20}; //Creates an array of 20 items.
vector<int> v1{^{20, 30, 40}}; //Creates an array of 3 items.
vector<int> v1{^20, 30, 40}; //Compiler error; no appropriate constructor to call.</pre><p>The question then becomes whether constr-braced-init-list should retain the
<span class="emphasis"><em>other</em></span> similarities to regular braced-init-lists. Should
this be allowed:</p><pre class="programlisting">array<int, 3> a1{^10, 20, 30};</pre><p>That is, do we want to forbid constr-braced-init-lists from initializing with
anything other than non-initializer_list constructors?</p><p>I would say no, and here is why.</p><p>Currently, <code class="function">std::allocator_traits::construct</code> is defined in
terms of calling <code class="literal">new(/*stuff*/)
T(std::forward<Args>(args)...)</code>. That will call constructors, but it
will <span class="emphasis"><em>only</em></span> call constructors. If we have a simple struct that
could use aggregate initialization, we cannot use, for example,
<code class="function">emplace</code> on it:</p><pre class="programlisting">struct Agg {int first, int second};
std::vector<Agg> ag{{10, 20}, {20, 30}, {30, 40}}; //Aggregate initialization is OK here.
ag.emplace_back(10, 20); //Error: no aggregate initialization is possible.</pre><p>There is no reason why we shouldn't be able to do this. To have this, we would
need to be able to have std::allocator_traits::construct use uniform initialization
syntax: <code class="literal">new(/*stuff*/) T{std::forward<Args>(args)...}</code>.
However, this can hide constructors;
<code class="literal">vector<vector<int>>::emplace_back(10)</code> will add a vector
containing one element. This will break existing applications, not to mention make
it completely impossible to access the hidden constructors via
<code class="function">emplace</code>.</p><p>By defining constr-braced-init-lists as being exactly equal to braced-init-list
except for which constructors it prefers, it makes it possible to redefine
<code class="function">std::allocator_traits::construct</code> in terms of
<code class="function">constr-braced-init-lists</code>. This now means that the
<code class="function">emplace</code> calls can access aggregate initialization if the
type supports it.</p></div><div class="section" title="Change the Definition"><div class="titlepage"><div><div><h3 class="title"><a name="d0e315"></a>Change the Definition</h3></div></div></div><p>There was an alternate design to resolve the issue. Simply declare that
non-<span class="type">initializer_list</span> constructors have priority, instead of the
other way around. This would make these completely unambiguous:</p><pre class="programlisting">std::vector<int> v1{20};
std::vector<int> v2{{20}};</pre><p><span class="type">v1</span> is using the <span class="type">size_type</span> constructor. <span class="type">v2</span>
is clearly calling a single-argument constructor using a braced-init-list.</p><p>The obvious problem with this is that it is a breaking change and a
<span class="emphasis"><em>silent</em></span> one at that.</p><p>Even worse, it doesn't look uniform:</p><pre class="programlisting">std::array<int, 6> a1 = {1, 2, 3, 4, 5, 6}; //Brace elision removes the extra pair.
std::vector<int> v1 = {1, 2, 3, 4, 5, 6}; //Brace "elision" possible.
std::array<int, 1> a2 = {1}; //Brace elision still works.
std::vector<int> v2 = {1}; //Brace "elision" no longer possible due to conflict. Does the wrong thing.</pre><p>Honestly, this would be the preferable solution, if it were not a breaking change.
But it is, so we probably shouldn't do it.</p></div></div></div></body></html>
------=_Part_337_15959070.1356904161500--
.
Author: =?UTF-8?Q?Klaim_=2D_Jo=C3=ABl_Lamotte?= <mjklaim@gmail.com>
Date: Mon, 31 Dec 2012 01:06:44 +0100
Raw View
--e89a8ff1c686dcd40004d21ac9ab
Content-Type: text/plain; charset=ISO-8859-1
Hi,
I'm not a C++ committee member but this document seems very convincing to
me.
(and scary where the problems are exposed).
A small suggestion to add to the bikeshedding list when this will be
discussed: using ':'
std::vector<int> v = {: 1, 2, 3 };
':' is not an operator so it makes things less ambiguous than operators
like ^ or | that look like some mathematic or bit-wise operation is
happening, even if the syntax is still invalid C++11.
Actually I don't really "like" having another strange syntax, but so far I
don't see how this could be fixed without the silently breaking change.
Maybe there's a way to do this change and add another change that would
make the first change non-silent?
Joel Lamotte
--
--e89a8ff1c686dcd40004d21ac9ab
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Hi,<div><br></div><div style>I'm not a C++ committee m=
ember but this document seems very convincing to me.</div><div style>(and s=
cary where the problems are exposed).<br><br>A small suggestion to add to t=
he=A0bikeshedding=A0list when this will be discussed: using ':'=A0<=
/div>
<div style>std::vector<int> v =3D {: 1, 2, 3 };<br><br>':' is=
not an operator so it makes things less ambiguous than operators like ^ or=
| that look like some mathematic or=A0bit-wise=A0operation is happening, e=
ven if the syntax is still invalid C++11.</div>
<div style><br></div><div style>Actually I don't really "like"=
; having another strange syntax, but so far I don't see how this could =
be fixed without the silently breaking change.<br>Maybe there's a way t=
o do this change and add another change that would make the first change no=
n-silent?=A0</div>
<div style><br></div><div style>Joel Lamotte</div></div>
<p></p>
-- <br />
<br />
<br />
<br />
--e89a8ff1c686dcd40004d21ac9ab--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sun, 30 Dec 2012 17:18:38 -0800 (PST)
Raw View
------=_Part_1812_14521544.1356916718284
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Sunday, December 30, 2012 4:06:44 PM UTC-8, Klaim - Jo=EBl Lamotte wrote=
:
>
> Hi,
>
> I'm not a C++ committee member but this document seems very convincing to=
=20
> me.
> (and scary where the problems are exposed).
>
> A small suggestion to add to the bikeshedding list when this will be=20
> discussed: using ':'=20
> std::vector<int> v =3D {: 1, 2, 3 };
>
> ':' is not an operator so it makes things less ambiguous than operators=
=20
> like ^ or | that look like some mathematic or bit-wise operation is=20
> happening, even if the syntax is still invalid C++11.
>
> Actually I don't really "like" having another strange syntax, but so far =
I=20
> don't see how this could be fixed without the silently breaking change.
> Maybe there's a way to do this change and add another change that would=
=20
> make the first change non-silent?=20
>
The only way to make it a noisy change would be to force {} to *only* use=
=20
initializer_list constructors (or aggregate initialization). That is, it=20
could never select a non-initializer_list constructor. I'll add it to the=
=20
list of alternatives, but I highly doubt they'd go for it.=20
>
> Joel Lamotte
>
--=20
------=_Part_1812_14521544.1356916718284
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Sunday, December 30, 2012 4:06:44 PM UTC-8, Klaim - Jo=EBl Lamot=
te wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: =
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">Hi,<=
div><br></div><div>I'm not a C++ committee member but this document seems v=
ery convincing to me.</div><div>(and scary where the problems are exposed).=
<br><br>A small suggestion to add to the bikeshedding list when t=
his will be discussed: using ':' </div>
<div>std::vector<int> v =3D {: 1, 2, 3 };<br><br>':' is not an operat=
or so it makes things less ambiguous than operators like ^ or | that look l=
ike some mathematic or bit-wise operation is happening, even if t=
he syntax is still invalid C++11.</div>
<div><br></div><div>Actually I don't really "like" having another strange s=
yntax, but so far I don't see how this could be fixed without the silently =
breaking change.<br>Maybe there's a way to do this change and add another c=
hange that would make the first change non-silent? </div></div></block=
quote><div><br>The only way to make it a noisy change would be to force {} =
to <i>only</i> use initializer_list constructors (or aggregate initializati=
on). That is, it could never select a non-initializer_list constructor. I'l=
l add it to the list of alternatives, but I highly doubt they'd go for it. =
<br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:=
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">
<div><br></div><div>Joel Lamotte</div></div>
</blockquote>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1812_14521544.1356916718284--
.
Author: Nevin Liber <nevin@eviloverlord.com>
Date: Mon, 31 Dec 2012 15:15:05 -0600
Raw View
--000e0cd3b600488b4104d22c846b
Content-Type: text/plain; charset=ISO-8859-1
On 30 December 2012 15:49, Nicol Bolas <jmckesson@gmail.com> wrote:
> {^ ... }
>
Having yet another way to do initialization scares me; it adds a lot of
complexity to the language overall, and I remain unconvinced it has enough
bang for the buck.
It doesn't address all the problems people have now. Another "gotcha" is
preferring
template<typename T>
Foo::Foo(T&& foo)
over
Foo::Foo(Foo const&)
for non-const references to Foo objects.
Given our past experience, I have very little confidence that we will now
solve the problem of uniform initialization once and for all.
> Library vs Language
>
> Originally, I considered a library-based solution to the issue. This would
> have required adding a special opaque type taken as a parameter to various
> calls. Since the opaque type is different from other types, it would
> prevent the braced-init-list from binding to an initializer_listconstructor, thus disambiguating the call.
>
There are other uses for this in containers; namely, it would be nice if
there was a syntax for default constructing elements in a container (as
opposed to value constructing them).
> First, it adds some complexity to various container classes, as they have
> to prevent the user from using the opaque type as the member or allocator
> types.
>
The way around that is to embed the type inside the container.
> --
>
Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404
--
--000e0cd3b600488b4104d22c846b
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On 30 December 2012 15:49, Nicol Bolas <span dir=3D"ltr"><<a href=3D"mai=
lto:jmckesson@gmail.com" target=3D"_blank">jmckesson@gmail.com</a>></spa=
n> wrote:<br><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" s=
tyle=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div title=3D"Design Overview"><p><span class=3D"Apple-style-span" style=3D=
"font-family:monospace;white-space:pre">{^ ... }</span></p></div></blockquo=
te><div><br></div><div>Having yet another way to do initialization scares m=
e; it adds a lot of complexity to the language overall, and I remain unconv=
inced it has enough bang for the buck.</div>
<div><br></div><div>It doesn't address all the problems people have now=
.. =A0Another "gotcha" is preferring</div><div><br></div><div>temp=
late<typename T></div><div>Foo::Foo(T&& foo)</div><div><br>
</div><div>over</div><div><br></div><div>Foo::Foo(Foo const&)</div><div=
><br></div><div>for non-const references to Foo objects.</div><div><br></di=
v><div>Given our past experience, I have very little confidence that we wil=
l now solve the problem of uniform initialization once and for all.</div>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div title=3D"Design Decisions"><div title=
=3D"Library vs Language"><div><div><div><h3>Library vs Language</h3></div><=
/div>
</div>
<p>Originally, I considered a library-based solution to the issue. This wou=
ld have
required adding a special opaque type taken as a parameter =
to various calls. Since
the opaque type is different from other types, it would pre=
vent the braced-init-list
from binding to an <span>initializer_list</span> constructo=
r, thus disambiguating
the call.</p></div></div></blockquote><div><br></div><div>T=
here are other uses for this in containers; namely, it would be nice if the=
re was a syntax for default constructing elements in a container (as oppose=
d to value constructing them).</div>
<div>=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;=
border-left:1px #ccc solid;padding-left:1ex"><div title=3D"Design Decisions=
"><div title=3D"Library vs Language"><p>First, it adds some complexity to v=
arious
container classes, as they have to prevent the user from us=
ing the opaque type as
the member or allocator types.</p></div></div></blockquote>=
<div>The way around that is to embed the type inside the container.</div><b=
lockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px =
#ccc solid;padding-left:1ex">
<div title=3D"Design Decisions"><div title=3D"Library vs Language"><p>--=A0=
</p></div></div></blockquote></div>=A0Nevin ":-)" Liber=A0 <ma=
ilto:<a href=3D"mailto:nevin@eviloverlord.com" target=3D"_blank">nevin@evil=
overlord.com</a>>=A0 (847) 691-1404
<p></p>
-- <br />
<br />
<br />
<br />
--000e0cd3b600488b4104d22c846b--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Mon, 31 Dec 2012 13:45:29 -0800 (PST)
Raw View
------=_Part_991_14525256.1356990329569
Content-Type: multipart/alternative;
boundary="----=_Part_992_17500137.1356990329569"
------=_Part_992_17500137.1356990329569
Content-Type: text/plain; charset=ISO-8859-1
On Monday, December 31, 2012 1:15:05 PM UTC-8, Nevin ":-)" Liber wrote:
>
> On 30 December 2012 15:49, Nicol Bolas <jmck...@gmail.com <javascript:>>wrote:
>
>> {^ ... }
>>
>
> Having yet another way to do initialization scares me; it adds a lot of
> complexity to the language overall, and I remain unconvinced it has enough
> bang for the buck.
>
Do you use uniform initialization now? If not, why not? If you don't, it's
generally for one of three reasons: your compiler of choice doesn't support
it, the initializer_list preference makes it impossible to always get the
constructor call you want, or you just don't feel like it. I can't do
anything about the first or third, but this proposal aims to solve the
second. That's important.
> It doesn't address all the problems people have now. Another "gotcha" is
> preferring
>
> template<typename T>
> Foo::Foo(T&& foo)
>
> over
>
> Foo::Foo(Foo const&)
>
> for non-const references to Foo objects.
>
That is completely orthogonal to uniform initialization. This isn't a
"resolve everything about initialization" issue; this is a "let's fix this
one particular problem" issue. Other issues should get their own fixes.
Unless you believe that this problem is somehow related to how
braced-init-lists do overload resolution, this problem has nothing to do
with the one that I'm proposing a fix for.
The problem you're talking about is not a *uniform initialization* problem.
Initialization is uniform with regard to non-const references to Foo; it
will always pick the same constructor. It simply doesn't pick the one you
wanted. That's not a problem with using braced-init-lists; that's a problem
with overload resolution rules *in general*. If you want to propose a fix
for that, feel free, but that fix will be completely orthogonal to this one.
> Given our past experience, I have very little confidence that we will now
> solve the problem of uniform initialization once and for all.
>
We don't need to solve the problem once and for all; we just need to make
things better.
> Library vs Language
>>
>> Originally, I considered a library-based solution to the issue. This
>> would have required adding a special opaque type taken as a parameter to
>> various calls. Since the opaque type is different from other types, it
>> would prevent the braced-init-list from binding to an initializer_listconstructor, thus disambiguating the call.
>>
>
> There are other uses for this in containers; namely, it would be nice if
> there was a syntax for default constructing elements in a container (as
> opposed to value constructing them).
>
Yes, but that is orthogonal to the issue of making braced-init-lists call
non-initializer_list constructors. I know; I actually wrote up a unified
proposal that included both of these. I'll attach it to this post, but I
abandoned the unified proposal because of the *other* issue: it doesn't
resolve the problem *in general*. It only solves it for the standard
library, so everyone has to manually implement the solution, which is not
something that can be done automatically and requires great care.
A problem introduced by a language feature should be solved by a language
feature. Forcing *everyone* to implement a workaround is not a solution.
>
>
>> First, it adds some complexity to various container classes, as they have
>> to prevent the user from using the opaque type as the member or allocator
>> types.
>>
> The way around that is to embed the type inside the container.
>
Which forces you to do this:
std::vector<int> v{1, std::vector<int>::value_init};
As far as I'm concerned, that's *unacceptably* ugly.
`std::piecewise_construct_t` isn't part of std::pair, for obvious reasons.
So why should `value_init` or `default_init` be part of it?
--
------=_Part_992_17500137.1356990329569
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Monday, December 31, 2012 1:15:05 PM UTC-8, Nevin ":-)" Liber wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">On 30 December 2012 15:49,=
Nicol Bolas <span dir=3D"ltr"><<a href=3D"javascript:" target=3D"_blank=
" gdf-obfuscated-mailto=3D"pTv94bJkgqwJ">jmck...@gmail.com</a>></span> w=
rote:<br><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=
=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div title=3D"Design Overview"><p><span style=3D"font-family:monospace;whit=
e-space:pre">{^ ... }</span></p></div></blockquote><div><br></div><div>Havi=
ng yet another way to do initialization scares me; it adds a lot of complex=
ity to the language overall, and I remain unconvinced it has enough bang fo=
r the buck.</div></div></blockquote><div><br>Do you use uniform initializat=
ion now? If not, why not? If you don't, it's generally for one of three rea=
sons: your compiler of choice doesn't support it, the initializer_list pref=
erence makes it impossible to always get the constructor call you want, or =
you just don't feel like it. I can't do anything about the first or third, =
but this proposal aims to solve the second. That's important.<br> </di=
v><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;"><div class=3D"gmail_quote"><=
div>It doesn't address all the problems people have now. Another "got=
cha" is preferring</div><div><br></div><div>template<typename T></div=
><div>Foo::Foo(T&& foo)</div><div><br>
</div><div>over</div><div><br></div><div>Foo::Foo(Foo const&)</div><div=
><br></div><div>for non-const references to Foo objects.</div></div></block=
quote><div><br>That is completely orthogonal to uniform initialization. Thi=
s isn't a "resolve everything about initialization" issue; this is a "let's=
fix this one particular problem" issue. Other issues should get their own =
fixes. Unless you believe that this problem is somehow related to how brace=
d-init-lists do overload resolution, this problem has nothing to do with th=
e one that I'm proposing a fix for.<br><br>The problem you're talking about=
is not a <i>uniform initialization</i> problem. Initialization is uniform =
with regard to non-const references to Foo; it will always pick the same co=
nstructor. It simply doesn't pick the one you wanted. That's not a problem =
with using braced-init-lists; that's a problem with overload resolution rul=
es <i>in general</i>. If you want to propose a fix for that, feel free, but=
that fix will be completely orthogonal to this one.<br> </div><blockq=
uote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-lef=
t: 1px #ccc solid;padding-left: 1ex;"><div class=3D"gmail_quote"><div></div=
><div>Given our past experience, I have very little confidence that we will=
now solve the problem of uniform initialization once and for all.</div></d=
iv></blockquote><div><br>We don't need to solve the problem once and for al=
l; we just need to make things better.<br> </div><blockquote class=3D"=
gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc so=
lid;padding-left: 1ex;"><div class=3D"gmail_quote">
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div title=3D"Design Decisions"><div title=
=3D"Library vs Language"><div><div><div><h3>Library vs Language</h3></div><=
/div>
</div>
<p>Originally, I considered a library-based solution to the issue. This wou=
ld have
required adding a special opaque type taken as a parameter =
to various calls. Since
the opaque type is different from other types, it would pre=
vent the braced-init-list
from binding to an <span>initializer_list</span> constructo=
r, thus disambiguating
the call.</p></div></div></blockquote><div><br></div><div>T=
here are other uses for this in containers; namely, it would be nice if the=
re was a syntax for default constructing elements in a container (as oppose=
d to value constructing them).</div></div></blockquote><div><br>Yes, but th=
at is orthogonal to the issue of making braced-init-lists call non-initiali=
zer_list constructors. I know; I actually wrote up a unified proposal that =
included both of these. I'll attach it to this post, but I abandoned the un=
ified proposal because of the <i>other</i> issue: it doesn't resolve the pr=
oblem <i>in general</i>. It only solves it for the standard library, so eve=
ryone has to manually implement the solution, which is not something that c=
an be done automatically and requires great care.<br><br>A problem introduc=
ed by a language feature should be solved by a language feature. Forcing <i=
>everyone</i> to implement a workaround is not a solution.<br> </div><=
blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bord=
er-left: 1px #ccc solid;padding-left: 1ex;"><div class=3D"gmail_quote">
<div> </div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8=
ex;border-left:1px #ccc solid;padding-left:1ex"><div title=3D"Design Decisi=
ons"><div title=3D"Library vs Language"><p>First, it adds some complexity t=
o various
container classes, as they have to prevent the user from us=
ing the opaque type as
the member or allocator types.</p></div></div></blockquote>=
<div>The way around that is to embed the type inside the container.</div></=
div></blockquote><div><br>Which forces you to do this:<br><br><div class=3D=
"prettyprint" style=3D"background-color: rgb(250, 250, 250); border-color: =
rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wrap: brea=
k-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify">std</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify">vector</span><span style=3D"color: #080;=
" class=3D"styled-by-prettify"><int></span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> v</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">{</span><span style=3D"color: #066;" class=3D"style=
d-by-prettify">1</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> st=
d</span><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify">vector</span><spa=
n style=3D"color: #080;" class=3D"styled-by-prettify"><int></span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">value_init</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">};</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"><br></span></div></code></div><br>As=
far as I'm concerned, that's <i>unacceptably</i> ugly. `std::piecewise_con=
struct_t` isn't part of std::pair, for obvious reasons. So why should `valu=
e_init` or `default_init` be part of it?</div><br>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_992_17500137.1356990329569--
------=_Part_991_14525256.1356990329569
Content-Type: text/html; charset=US-ASCII;
name="Improved Container Initialization.html"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="Improved Container Initialization.html"
X-Attachment-Id: bc75677e-693e-4063-8d25-9c9413f36d5b
<html><head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3DISO=
-8859-1">
<title>Improved Container Initialization</title><meta name=3D"generator"=
content=3D"DocBook XSL-NS Stylesheets V1.75.2"></head><body bgcolor=3D"whi=
te" text=3D"black" link=3D"#0000FF" vlink=3D"#840084" alink=3D"#0000FF"><di=
v class=3D"article" title=3D"Improved Container Initialization"><div class=
=3D"titlepage"><div><div><h2 class=3D"title"><a name=3D"d0e3"></a>Improved =
Container Initialization</h2></div></div><hr></div><div class=3D"toc"><p><b=
>Table of Contents</b></p><dl><dt><span class=3D"section"><a href=3D"#d0e6"=
>Introduction</a></span></dt><dt><span class=3D"section"><a href=3D"#d0e16"=
>Motivation and Scope</a></span></dt><dd><dl><dt><span class=3D"section"><a=
href=3D"#d0e21">Uniform Initialization Ambiguity</a></span></dt><dt><span =
class=3D"section"><a href=3D"#d0e65">Value Initialized Containers</a></span=
></dt></dl></dd><dt><span class=3D"section"><a href=3D"#d0e115">Design Over=
view</a></span></dt><dd><dl><dt><span class=3D"section"><a href=3D"#d0e131"=
>Default and Value Initialization</a></span></dt><dt><span class=3D"section=
"><a href=3D"#d0e223">Other Disambiguation</a></span></dt><dt><span class=
=3D"section"><a href=3D"#d0e252">Overload Ambiguity Resolution</a></span></=
dt></dl></dd><dt><span class=3D"section"><a href=3D"#d0e281">Impact on the =
Standard</a></span></dt><dt><span class=3D"section"><a href=3D"#d0e308">Des=
ign Decisions</a></span></dt><dd><dl><dt><span class=3D"section"><a href=3D=
"#d0e311">Disambiguation of Functions</a></span></dt><dt><span class=3D"sec=
tion"><a href=3D"#d0e320">ABI Minimization</a></span></dt><dt><span class=
=3D"section"><a href=3D"#d0e325">Naming</a></span></dt></dl></dd><dt><span =
class=3D"section"><a href=3D"#d0e354">Technical Specifications</a></span></=
dt><dd><dl><dt><span class=3D"section"><a href=3D"#d0e359">Utility</a></spa=
n></dt><dt><span class=3D"section"><a href=3D"#d0e410">basic_string</a></sp=
an></dt><dt><span class=3D"section"><a href=3D"#d0e727">Container requireme=
nts</a></span></dt><dt><span class=3D"section"><a href=3D"#d0e747">deque</a=
></span></dt><dt><span class=3D"section"><a href=3D"#d0e758">forward_list</=
a></span></dt><dt><span class=3D"section"><a href=3D"#d0e769">list</a></spa=
n></dt><dt><span class=3D"section"><a href=3D"#d0e780">vector</a></span></d=
t></dl></dd><dt><span class=3D"section"><a href=3D"#d0e791">Acknowledgement=
s</a></span></dt><dt><span class=3D"section"><a href=3D"#d0e796">References=
</a></span></dt></dl></div><div class=3D"section" title=3D"Introduction"><d=
iv class=3D"titlepage"><div><div><h2 class=3D"title" style=3D"clear: both">=
<a name=3D"d0e6"></a>Introduction</h2></div></div></div><p>Uniform initiali=
zation can be used in almost all circumstances. However, there are
times when <code class=3D"literal">initializer_list</code> cons=
tructors conflict with regular
constructors. In those cases, an extra argument is needed, whic=
h is of a different type
than other arguments, to disambiguate the call and correctly se=
lect one from the
other.</p><p>The difference between default initialization and =
value initialization in C++ is
important for performance in many circumstances. Many users res=
trict a class definition
to keep it within the “trivial” category deliberate=
ly to take advantage of essentially
free default construction. However, many standard library conta=
iners do not allow the
user to default initialize the contents of a class, forcing the=
user to value-initialize
objects unnecessarily.</p></div><div class=3D"section" title=3D=
"Motivation and Scope"><div class=3D"titlepage"><div><div><h2 class=3D"titl=
e" style=3D"clear: both"><a name=3D"d0e16"></a>Motivation and Scope</h2></d=
iv></div></div><p>This proposal solves two different problems. They are bot=
h part of the same proposal
because they look very similar to the user in many cases and at=
tempt to complement one
another.</p><div class=3D"section" title=3D"Uniform Initializat=
ion Ambiguity"><div class=3D"titlepage"><div><div><h3 class=3D"title"><a na=
me=3D"d0e21"></a>Uniform Initialization Ambiguity</h3></div></div></div><p>=
Uniform initialization is intended to be uniform, hence the name. However, =
because
uniform initialization ties into initializer_list initializ=
ation, it can cause
conflicts. Consider the following code.</p><pre class=3D"pr=
ogramlisting">std::vector<int> intVec1(43);
std::vector<int> intVec2{43};</pre><p>These look the same, and one wo=
uld expect them to behave the same. But they are
not the same. <code class=3D"literal">intVec1</code> is a v=
ector of 43 value-constructed
integers. <code class=3D"literal">intVec2</code> is a vecto=
r of a single integer, 43. The
wording of the standard dictates that the <code class=3D"li=
teral">initializer_list</code>
constructors always have priority when matching against a b=
raced-init-list. And
since this is a <code class=3D"literal">vector<int></=
code>, the
<code class=3D"literal">initializer_list</code> constru=
ctor will be selected.</p><p>Indeed, there is absolutely no way to call the
<code class=3D"literal">std::vector<int>::vector(=
size_type)</code> constructor with a
braced-init-list. There is no way to call the constructor t=
hat takes a
<code class=3D"literal">size_type</code> and an integer=
default either. If you use uniform
initialization with a <code class=3D"literal">vector<int=
></code>, you will always be using
the <code class=3D"literal">initializer_list</code> constru=
ctor with these.</p><p>This also happens when attempting to use sized const=
ruction with an explicit value
to copy from:</p><pre class=3D"programlisting">std::vector&=
lt;int> intVec1(43, 3); //43 element vector of 3's.
std::vector<int> intVec2{43, 3}; //2 element vector.</pre><p>This is =
not very uniform initialization.</p></div><div class=3D"section" title=3D"V=
alue Initialized Containers"><div class=3D"titlepage"><div><div><h3 class=
=3D"title"><a name=3D"d0e65"></a>Value Initialized Containers</h3></div></d=
iv></div><p>Consider the following code.</p><pre class=3D"programlisting">a=
uto *largeArray =3D new std::array<int, 50000000>;
std::vector<int> largeVector(50000000);</pre><p>One of these takes su=
bstantially longer than the other. They should not. They both
allocate roughly the same amount of memory. Yet the initial=
ization of the
<code class=3D"literal">vector</code> takes much longer=
.. With further profiling, we would
also discover that the <code class=3D"literal">vector</code=
> creation's running time is linear
in the number of elements.</p><p>The reason for this is tha=
t <code class=3D"literal">vector</code> is required to initialize
all of its arguments with
<code class=3D"literal">allocator_traits<Allocator&g=
t;::construct</code> for the all, which
will either call <code class=3D"literal">a.construct</code>=
with an empty argument list, or
<code class=3D"literal">new(memory) int()</code>. Both =
of which will perform value
initialization on the contents.</p><p>While the relative ti=
me of value-initializing 50 million integers is not that
long, consider the following code design.</p><pre class=3D"=
programlisting">int imageSize =3D width * height * 4;
std::vector<uint32_t> imageData(imageSize);
FetchImageData(..., imageData.data(), imageSize);</pre><p>This is not uncom=
mon. The above mimics behavior that might be found in a video or
image decompression system. It loads some image data intern=
ally, and decompresses it
into storage you provide. There are many APIs that expect y=
ou to pass in a pointer
and size in bytes, and they will fill them in. C++ users wa=
nt to use a
<code class=3D"literal">std::vector</code> or <code cla=
ss=3D"literal">std::string</code> to allocate and
manage that memory. However, when they do so, they also get=
pointless value
initialization.</p><p>This often prompts users to do this i=
nstead:</p><pre class=3D"programlisting">int imageSize =3D width * height *=
4;
std::unique_ptr<uint32_t[]> pImageData{new uint32_t[imageSize]};
FetchImageData(..., imageData.data(), imageSize);</pre><p>This provides the=
proper memory management, but absolutely none of the other
conveniences of <code class=3D"literal">std::vector</code>.=
It doesn't even store the size
internally.</p></div></div><div class=3D"section" title=3D"=
Design Overview"><div class=3D"titlepage"><div><div><h2 class=3D"title" sty=
le=3D"clear: both"><a name=3D"d0e115"></a>Design Overview</h2></div></div><=
/div><p>The general idea to solve both problems is to introduce functions w=
ith new arguments
to designate which kinds of things are being called. Part of th=
e reason that these
proposals are linked is because they use the same mechanism, so=
the names and types of
constructs are similar in order to acknowledge the similarities=
..</p><p>The following overview focuses on <code class=3D"literal">std::vect=
or</code>, but they all of the
sequence containers (except for <code class=3D"literal">array</=
code>, but including
<code class=3D"literal">basic_string</code>) will have simi=
lar functions.</p><div class=3D"section" title=3D"Default and Value Initial=
ization"><div class=3D"titlepage"><div><div><h3 class=3D"title"><a name=3D"=
d0e131"></a>Default and Value Initialization</h3></div></div></div><p>To al=
low default initialization of values implies that there should be an explic=
it
way to value-initialize members too. There are a lot of fun=
ctions that only take a
value to copy into each value; only the main constructors h=
ave an overload
specifically for value-initialization. So we solve this pro=
blem while also
disambiguating the constructor.</p><p>To allow for default =
or value initialization of the various types, we will add two
constructors, one for default initialization and one for va=
lue
initialization:</p><pre class=3D"programlisting">vector(siz=
e_type n, value_init_t, const Allocator& =3D Allocator());
vector(size_type n, default_init_t, const Allocator& =3D Allocator());<=
/pre><p>The types <code class=3D"literal">value_init_t</code> and <code cla=
ss=3D"literal">default_init_t</code>
are much like the standard type <code class=3D"literal">pie=
cewise_construct_t</code>. They are
empty <code class=3D"literal">struct</code>s used to disamb=
iguate function calls.</p><p>These constructors are called with <code class=
=3D"literal">constexpr</code> variables as shown
below:</p><pre class=3D"programlisting">std::vector<int&=
gt; intVec1{43, std::value_init);
std::vector<int> intVec2{43, std::default_init};</pre><p>The meaning =
of the <code class=3D"literal">value_init</code> constructor is the same as=
the
constructor that only takes a <code class=3D"literal">size_=
type</code>. This, the
<code class=3D"literal">value_init</code> case formally=
disambiguates the constructor from
braced-init-lists. The behavior of <code class=3D"literal">=
default_init</code> is a bit more
complex.</p><p>The <code class=3D"literal">allocator_traits=
<Allocator>::construct</code> cannot
default-construct the types. Therefore, we will need to ext=
end
<code class=3D"literal">allocator_traits</code> with a =
new function:
<code class=3D"literal">default_construct</code>. This =
will call either
<code class=3D"literal">a.default_construct</code> or i=
f that is not available,
<code class=3D"literal">::new(p) T</code>, without the =
parentheses.</p><p>Value and default initialization overloads will be added=
for the following
functions:</p><div class=3D"itemizedlist"><ul class=3D"item=
izedlist" type=3D"disc"><li class=3D"listitem"><p>Sized constructors.</p></=
li><li class=3D"listitem"><p><code class=3D"literal">insert</code></p></li>=
<li class=3D"listitem"><p><code class=3D"literal">push_back/front</code></p=
></li><li class=3D"listitem"><p><code class=3D"literal">append</code></p></=
li><li class=3D"listitem"><p><code class=3D"literal">assign</code></p></li>=
<li class=3D"listitem"><p><code class=3D"literal">resize</code></p></li></u=
l></div><p>Note that in all cases, these are overloads that are <span class=
=3D"emphasis"><em>added</em></span>.
No existing functions are modified.</p></div><div class=3D"=
section" title=3D"Other Disambiguation"><div class=3D"titlepage"><div><div>=
<h3 class=3D"title"><a name=3D"d0e223"></a>Other Disambiguation</h3></div><=
/div></div><p><code class=3D"literal">value_init_t</code> is able to serve =
as a way to disambiguate the
sizing constructors that perform value initialization. Howe=
ver, it would be
inappropriate, from a nomenclature perspective, to use it f=
or disambiguating this
constructor:</p><pre class=3D"programlisting">vector(size_t=
ype n, const T& value, const Allocator& a =3D Allocator());</pre><p=
>If <code class=3D"literal">T</code> is an integer type, and you wish to co=
nstruct it from two
integers, there needs to be a way to disambiguate this case=
from an initializer list
of integers. We do this with a third type, which provides t=
his constructor
overload:</p><pre class=3D"programlisting">vector(size_type=
n, const T& value, disambiguate_t, const Allocator& a =3D Allocato=
r());</pre><p>The <code class=3D"literal">disambiguate_t</code> type is ano=
ther empty
<code class=3D"literal">struct</code>. It will have a <=
code class=3D"literal">constexpr</code> instance
variable that is as follows:</p><pre class=3D"programlistin=
g">std::vector<int> intVec2{43, 2, std::no_list};</pre></div><div cla=
ss=3D"section" title=3D"Overload Ambiguity Resolution"><div class=3D"titlep=
age"><div><div><h3 class=3D"title"><a name=3D"d0e252"></a>Overload Ambiguit=
y Resolution</h3></div></div></div><p>This has the potential to create ambi=
guity in function overloads, if one of the
special types is used as a template parameter. <code class=
=3D"literal">default_init_t</code> and
<code class=3D"literal">value_init_t</code> can be ambi=
guous if they are the value type. As
values, they create ambiguity between these constructors:</=
p><pre class=3D"programlisting">vector(size_type n, const T& value, con=
st Allocator& a =3D Allocator());
vector(size_type n, value_init_t, const Allocator& a =3D Allocator());
vector(size_type n, default_init_t, const Allocator& a =3D Allocator())=
;</pre><p>Similar ambiguity can occur for other functions.</p><p><code clas=
s=3D"literal">std::disambiguate_t</code> does not create ambiguity if it is=
the
value type. However, it can create them if it is the alloca=
tor type:</p><pre class=3D"programlisting">vector(size_type n, const T&=
value, std::disambiguate_t, const Allocator& a =3D Allocator());
vector(size_type n, const T& value, const Allocator& a =3D Allocato=
r());</pre><p>The simplest way to prevent this problem is to simply forbid =
the use of any of
these types in this way. All of the affected containers wil=
l have
<code class=3D"literal">static_assert</code>s that dete=
ct and prevent instantiations with
these types. To make sure that all cases are attended to, w=
e will forbid the use of
any of these types as the value type, traits type (for
<code class=3D"literal">basic_string</code>), or alloca=
tor type for these containers.</p></div></div><div class=3D"section" title=
=3D"Impact on the Standard"><div class=3D"titlepage"><div><div><h2 class=3D=
"title" style=3D"clear: both"><a name=3D"d0e281"></a>Impact on the Standard=
</h2></div></div></div><p>This will add two types to the standard library, =
almost certainly in <utility> due
to being used across multiple other libraries. It will add thre=
e
<code class=3D"literal">constexpr</code> values. It adds a =
new
<code class=3D"literal">allocator_traits</code> function.</=
p><p>Into each of the sequence containers save <code class=3D"literal">arra=
y</code> (and including
<code class=3D"literal">std::basic_string</code>), this pro=
posal will add new constructor
overloads, as well as modify existing ones by adding a default =
parameter. It will
require these types to have some <code class=3D"literal">static=
_assert</code>s to prevent improper
usage.</p><p>It will add a number of constructor and member fun=
ction overloads. It will
<span class=3D"emphasis"><em>not</em></span> modify any exi=
sting constructors, so no ABI breakage should
occur. It will add some failure conditions for instantiating ce=
rtain templates, but this
will only be for types that did not exist beforehand.</p></div>=
<div class=3D"section" title=3D"Design Decisions"><div class=3D"titlepage">=
<div><div><h2 class=3D"title" style=3D"clear: both"><a name=3D"d0e308"></a>=
Design Decisions</h2></div></div></div><div class=3D"section" title=3D"Disa=
mbiguation of Functions"><div class=3D"titlepage"><div><div><h3 class=3D"ti=
tle"><a name=3D"d0e311"></a>Disambiguation of Functions</h3></div></div></d=
iv><p>Adding new overloads, particularly of template types, always raises t=
he specter of
ambiguous overloads. It was necessary to forbid some uses o=
f these classes to
prevent this. By forbidding the use of control types such a=
s these, it gives us the
freedom to make potentially ambiguous functions by taking a=
way the ambiguity.</p><p>The design above forbids the use of the control ty=
pes in any of these containers.
We could admittedly forbid them only in specific uses that =
create ambiguity.
However, using empty objects like this as any template para=
meter of these containers
is pointless. And if the user wants to do so, they can crea=
te an empty type
themselves. This way, we gain greater consistency by bannin=
g all uses of them,
whether they create ambiguity or not. It helps the API feel=
more consistent.</p><p>I would submit that nothing of value is lost by add=
ing this restriction.</p></div><div class=3D"section" title=3D"ABI Minimiza=
tion"><div class=3D"titlepage"><div><div><h3 class=3D"title"><a name=3D"d0e=
320"></a>ABI Minimization</h3></div></div></div><p>The decision to add new =
constructor and function overloads instead of replacing
ones and using default parameters was made to ensure that n=
o ABI breakage would
occur. This proposal only adds new functions; it does not c=
hange any existing
ones.</p></div><div class=3D"section" title=3D"Naming"><div=
class=3D"titlepage"><div><div><h3 class=3D"title"><a name=3D"d0e325"></a>N=
aming</h3></div></div></div><p>Obviously, the use of <code class=3D"literal=
">value_init</code> is primarily to contrast with
<code class=3D"literal">default_init</code>, thus makin=
g it clearer exactly which is
happening. I'm not wedded to the <code class=3D"literal">no=
_list</code> name, but I think all of
them need separate names and types, so that it's clear what=
they're intended to do.
<code class=3D"literal">value_init</code> causes value-=
initialization. It pairs up with
<code class=3D"literal">default_init</code> for default=
initialization.
<code class=3D"literal">no_list</code> is just the gene=
ric term for disambiguating between
<code class=3D"literal">initializer_list</code> constru=
ction and
non-<code class=3D"literal">initializer_list</code> con=
struction.</p></div></div><div class=3D"section" title=3D"Technical Specifi=
cations"><div class=3D"titlepage"><div><div><h2 class=3D"title" style=3D"cl=
ear: both"><a name=3D"d0e354"></a>Technical Specifications</h2></div></div>=
</div><p>These specifications are written against section N3337.</p><div cl=
ass=3D"section" title=3D"Utility"><div class=3D"titlepage"><div><div><h3 cl=
ass=3D"title"><a name=3D"d0e359"></a>Utility</h3></div></div></div><p>In se=
ction 20.2, paragraph 2, add the following after the declaration of
<code class=3D"literal">declval</code>:</p><pre class=
=3D"programlisting">//20.2.5
struct value_init_t {};
constexpr value_init_t value_init;
struct default_init_t {};
constexpr default_init_t default_init;
struct disambiguate_t {};
constexpr disambiguate_t no_list;</pre><p>In section 20.6.8 [allocator.trai=
ts], paragraph 1, add the following into the
declaration of <code class=3D"literal">allocator_traits</co=
de>:</p><pre class=3D"programlisting">template <class T>
static void default_construct(Alloc& a, T* p);</pre><p>In section 20.6.=
8.2, [allocator.traits.members], after paragraph 5, add the
following:</p><div class=3D"blockquote"><blockquote class=
=3D"blockquote"><pre class=3D"programlisting">template <class T>
static void default_construct(Alloc& a, T* p);</pre><p><span class=3D"e=
mphasis"><em>Effects:</em></span> calls <code class=3D"literal">a.default_c=
onstruct(p)</code>
if that call is well-formed; otherwise, invokes <code c=
lass=3D"literal">::new
(static_cast<void*>(p)) T</code>.</p></blockq=
uote></div><p>In section 20.6.9, [default.allocator], add the following to =
the declaration of
<code class=3D"literal">std::allocator</code>:</p><pre =
class=3D"programlisting">template <class U>
static void default_construct(Alloc& a, U* p);</pre><p>In section 20.6.=
9.1 [allocator.members], after paragraph 12, add the
following:</p><div class=3D"blockquote"><blockquote class=
=3D"blockquote"><pre class=3D"programlisting">template <class U>
static void default_construct(Alloc& a, U* p);</pre><p><span class=3D"e=
mphasis"><em>Effects:</em></span> calls <code class=3D"literal">::new (stat=
ic_cast<void*>(p))
U</code>.</p></blockquote></div></div><div class=3D=
"section" title=3D"basic_string"><div class=3D"titlepage"><div><div><h3 cla=
ss=3D"title"><a name=3D"d0e410"></a>basic_string</h3></div></div></div><p>I=
n section 21.4, add the following declarations to
<code class=3D"literal">basic_string</code>, in their appro=
priate sections:</p><div class=3D"blockquote"><blockquote class=3D"blockquo=
te"><pre class=3D"programlisting">basic_string(size_type n, value_init_t, c=
onst Allocator& a =3D Allocator());</pre><p>Requires: <code class=3D"co=
de">n < npos</code></p><p>Effects: Constructs an object of class <code c=
lass=3D"literal">basic_string</code> and
determines its initial string value by value-initializi=
ng each char-like object
via a call to for n elements, as indicated in Table XX=
..</p><p>Table XX is like table 68, except that <code class=3D"literal">data=
()</code>
<span class=3D"quote">“<span class=3D"quote">poin=
ts at the first element of an allocated array of <code class=3D"literal">n<=
/code>
elements, each storing the initial value
<code class=3D"literal">charT()</code></span>”</s=
pan></p><pre class=3D"programlisting">basic_string(size_type n, default_ini=
t_t, const Allocator& a =3D Allocator());</pre><p>Requires: <code class=
=3D"code">n < npos</code></p><p>Effects: Constructs an object of class <=
code class=3D"literal">basic_string</code> and
determines its initial string value by default-initiali=
zing each char-like
object for n elements, as indicated in Table XY.</p><p>=
Table XY is like table 68, except that <code class=3D"literal">data()</code=
>
<span class=3D"quote">“<span class=3D"quote">poin=
ts at the first element of an allocated array of <code class=3D"literal">n<=
/code>
elements, who's initial values are undefined.</span=
>”</span></p><pre class=3D"programlisting">basic_string(size_type n, =
charT c, disambiguate_t, const Allocator& a =3D Allocator());</pre><p>E=
ffects: <code class=3D"code">basic_string(n, c, a)</code></p><pre class=3D"=
programlisting">void resize(size_type n, value_init_t);</pre><p>Effects: <c=
ode class=3D"code">resize(n, charT())</code></p><pre class=3D"programlistin=
g">void resize(size_type n, default_init_t);</pre><p>Requires: <code class=
=3D"code">n <=3D max_size()</code></p><p>Throws: <code class=3D"literal"=
>length_error</code> if <code class=3D"code">n > max_size()</code>.</p><=
p>Effects: Alters the length of the string designated by
<code class=3D"literal">*this</code> as follows:</p=
><div class=3D"itemizedlist"><ul class=3D"itemizedlist" type=3D"disc"><li c=
lass=3D"listitem"><p>If <code class=3D"code">n <=3D size()</code>, the f=
unction replaces the string
designated by <code class=3D"literal">*this</co=
de> with a string of length
<code class=3D"literal">n</code> whose elem=
ents are a copy of the initial
elements of the original string designated by
<code class=3D"literal">*this</code>.</p></li><=
li class=3D"listitem"><p>If <code class=3D"code">n > size()</code>, the =
function replaces the string
designated by <code class=3D"literal">*this</co=
de> with a string of length
<code class=3D"literal">n</code> whose firs=
t <code class=3D"literal">size()</code> elements
are a copy of the original string designated by
<code class=3D"literal">*this</code>, and whose=
remaining elements are
undefined.</p></li></ul></div><pre class=3D"pro=
gramlisting">basic_string& append(size_type n, value_init_t);</pre><p>E=
ffects: <code class=3D"code">append(n, charT())</code></p><p>Returns: <code=
class=3D"literal">*this</code></p><pre class=3D"programlisting">basic_stri=
ng& append(size_type n, default_init_t);</pre><p>Effects: Equivalent to=
<code class=3D"code">append(basic_string{n,
default_init_t{}})</code></p><p>Returns: <code class=3D=
"literal">*this</code></p><pre class=3D"programlisting">void push_back(valu=
e_init_t);</pre><p>Effects: <code class=3D"code">push_back(charT())</code><=
/p><pre class=3D"programlisting">void push_back(default_init_t);</pre><p>Ef=
fects: Equivalent to <code class=3D"code">append(static_cast<size_type&g=
t;(1),
default_init_t{})</code></p><pre class=3D"programli=
sting">basic_string& assign(size_type n, value_init_t);</pre><p>Effects=
: Equivalent to <code class=3D"code">assign(basic_string{n,
value_init_t{}})</code></p><pre class=3D"programlisting=
">basic_string& assign(size_type n, default_init_t);</pre><p>Effects: E=
quivalent to <code class=3D"code">assign(basic_string{n,
default_init_t{}})</code></p><pre class=3D"programlisti=
ng">basic_string& insert(size_type pos, size_type n, value_init_t);</pr=
e><p>Effects: Equivalent to <code class=3D"code">insert(pos, basic_string{n=
,
value_init_t{}})</code></p><p>Returns: <code class=
=3D"literal">*this</code></p><pre class=3D"programlisting">basic_string&=
; insert(size_type pos, size_type n, default_init_t);</pre><p>Effects: Equi=
valent to <code class=3D"code">insert(pos, basic_string{n,
default_init_t{}})</code></p><p>Returns: <code clas=
s=3D"literal">*this</code></p><pre class=3D"programlisting">iterator insert=
(const_iterator p, value_init_t);</pre><p>Requires: p is a valid iterator o=
n *this.</p><p>Effects: inserts a copy of <code class=3D"literal">charT()</=
code> before the character
referred to by <code class=3D"literal">p</code>.</p><p>=
Returns: An iterator which refers to the copy of the inserted
character.</p><pre class=3D"programlisting">iterator in=
sert(const_iterator p, default_init_t);</pre><p>Requires: p is a valid iter=
ator on *this.</p><p>Effects: inserts a default-initialized character befor=
e the character referred
to by <code class=3D"literal">p</code>.</p><p>Returns: =
An iterator which refers to the copy of the inserted
character.</p><pre class=3D"programlisting">iterator in=
sert(const_iterator p, size_type n, value_init_t);</pre><p>Requires: p is a=
valid iterator on *this.</p><p>Effects: inserts <code class=3D"literal">n<=
/code> copies of <code class=3D"literal">charT()</code>
before the character referred to by <code class=3D"lite=
ral">p</code>.</p><p>Returns: An iterator which refers to the first inserte=
d
<code class=3D"literal">charT()</code> character, o=
r <code class=3D"literal">p</code> if <code class=3D"code">n =3D=3D
0</code>.</p><pre class=3D"programlisting">iterator=
insert(const_iterator p, size_type n, default_init_t);</pre><p>Requires: p=
is a valid iterator on *this.</p><p>Effects: inserts <code class=3D"litera=
l">n</code> default-constructed characters before
the character referred to by <code class=3D"literal">p<=
/code>.</p><p>Returns: An iterator which refers to the first inserted defau=
lt-constructed
character, or <code class=3D"literal">p</code> if <code=
class=3D"code">n =3D=3D 0</code>.</p><pre class=3D"programlisting">basic_s=
tring& replace(size_type pos1, size_type n1, size_type n2, value_init_t=
);</pre><p>Effects: Equivalent to <code class=3D"code">replace(pos1, n1, ba=
sic_string{n2,
value_init_t{}})</code>.</p><p>Returns: <code class=
=3D"literal">*this</code>.</p><pre class=3D"programlisting">basic_string&am=
p; replace(size_type pos1, size_type n1, size_type n2, default_init_t);</pr=
e><p>Effects: Equivalent to <code class=3D"code">replace(pos1, n1, basic_st=
ring{n2,
default_init_t{}})</code>.</p><p>Returns: <code cla=
ss=3D"literal">*this</code>.</p><pre class=3D"programlisting">basic_string&=
amp; replace(const_iterator i1, const_iterator i2, size_type n, value_init_=
t);</pre><p>Requires: <code class=3D"code">[begin(),i1)</code> and <code cl=
ass=3D"code">[i1,i2)</code> are valid
ranges.</p><p>Effects: Calls <code class=3D"code">repla=
ce(i1 - begin(), i2 - i1, basic_string{n,
value_init_t{}})</code>.</p><p>Returns: <code class=
=3D"literal">*this</code>.</p><pre class=3D"programlisting">basic_string&am=
p; replace(const_iterator i1, const_iterator i2, size_type n, default_init_=
t);</pre><p>Requires: <code class=3D"code">[begin(),i1)</code> and <code cl=
ass=3D"code">[i1,i2)</code> are valid
ranges.</p><p>Effects: Calls <code class=3D"code">repla=
ce(i1 - begin(), i2 - i1, basic_string{n,
default_init_t{}})</code>.</p><p>Returns: <code cla=
ss=3D"literal">*this</code>.</p></blockquote></div></div><div class=3D"sect=
ion" title=3D"Container requirements"><div class=3D"titlepage"><div><div><h=
3 class=3D"title"><a name=3D"d0e727"></a>Container requirements</h3></div><=
/div></div><p>In section 23.2.1, [container.requirements.general], change t=
he first sentence of
paragraph 4 to read:</p><div class=3D"blockquote"><blockquo=
te class=3D"blockquote"><p>For the components affected by this subclause th=
at declare an
<code class=3D"literal">allocator_type</code>, obje=
cts stored in these components shall
be constructed using the
<code class=3D"literal">allocator_traits<allocat=
or_type>::construct</code> or
<code class=3D"literal">allocator_traits<allocat=
or_type>::default_construct</code>
functions and destroyed using the
<code class=3D"literal">allocator_traits<allocat=
or_type>::destroy</code> function
(20.6.8.2).</p></blockquote></div></div><div class=3D"s=
ection" title=3D"deque"><div class=3D"titlepage"><div><div><h3 class=3D"tit=
le"><a name=3D"d0e747"></a>deque</h3></div></div></div><p>In section 23.3.3=
..1, [deque.overview], paragraph 2, add the following declarations
to <code class=3D"literal">deque</code>:</p><div class=3D"b=
lockquote"><blockquote class=3D"blockquote"><pre class=3D"programlisting">d=
eque(size_type n, value_init_t, const Allocator& =3D Allocator());
deque(size_type n, default_init_t, const Allocator& =3D Allocator());
deque(size_type n, const T& value, disambiguate_t, const Allocator&=
a =3D Allocator());
void assign(size_type n, value_init_t);
void assign(size_type n, default_init_t);
void resize(size_type sz, value_init_t);
void resize(size_type sz, default_init_t);
void push_front(value_init_t);
void push_front(default_init_t);
void push_back(value_init_t);
void push_back(default_init_t);
iterator insert(const_iterator position, size_type n, value_init_t);
iterator insert(const_iterator position, size_type n, default_init_t);</pre=
></blockquote></div></div><div class=3D"section" title=3D"forward_list"><di=
v class=3D"titlepage"><div><div><h3 class=3D"title"><a name=3D"d0e758"></a>=
forward_list</h3></div></div></div><p>In section 23.3.4.1, [forwardlist.ove=
rview], paragraph 3, add the following
declarations to <code class=3D"literal">forward_list</code>=
:</p><div class=3D"blockquote"><blockquote class=3D"blockquote"><pre class=
=3D"programlisting">forward_list(size_type n, value_init_t, const Allocator=
& =3D Allocator());
forward_list(size_type n, default_init_t, const Allocator& =3D Allocato=
r());
forward_list(size_type n, const T& value, disambiguate_t, const Allocat=
or& a =3D Allocator());
void assign(size_type n, value_init_t);
void assign(size_type n, default_init_t);
void push_front(value_init_t);
void push_front(default_init_t);
iterator insert_after(const_iterator position, size_type n, value_init_t);
iterator insert_after(const_iterator position, size_type n, default_init_t)=
;
void resize(size_type sz, value_init_t);
void resize(size_type sz, default_init_t);</pre></blockquote></div></div><d=
iv class=3D"section" title=3D"list"><div class=3D"titlepage"><div><div><h3 =
class=3D"title"><a name=3D"d0e769"></a>list</h3></div></div></div><p>In sec=
tion 23.3.5.1, [list.overview], paragraph 2, add the following declarations
to <code class=3D"literal">list</code>:</p><div class=3D"bl=
ockquote"><blockquote class=3D"blockquote"><pre class=3D"programlisting">li=
st(size_type n, value_init_t, const Allocator& =3D Allocator());
list(size_type n, default_init_t, const Allocator& =3D Allocator());
list(size_type n, const T& value, disambiguate_t, const Allocator& =
a =3D Allocator());
void assign(size_type n, value_init_t);
void assign(size_type n, default_init_t);
void resize(size_type sz, value_init_t);
void resize(size_type sz, default_init_t);
void push_front(value_init_t);
void push_front(default_init_t);
void push_back(value_init_t);
void push_back(default_init_t);
iterator insert(const_iterator position, size_type n, value_init_t);
iterator insert(const_iterator position, size_type n, default_init_t);</pre=
></blockquote></div></div><div class=3D"section" title=3D"vector"><div clas=
s=3D"titlepage"><div><div><h3 class=3D"title"><a name=3D"d0e780"></a>vector=
</h3></div></div></div><p>In section 23.3.6.1, [vector.overview], paragraph=
2, add the following
declarations to <code class=3D"literal">vector</code>:</p><=
div class=3D"blockquote"><blockquote class=3D"blockquote"><pre class=3D"pro=
gramlisting">vector(size_type n, value_init_t, const Allocator& =3D All=
ocator());
vector(size_type n, default_init_t, const Allocator& =3D Allocator());
vector(size_type n, const T& value, disambiguate_t, const Allocator&=
; a =3D Allocator());
void assign(size_type n, value_init_t);
void assign(size_type n, default_init_t);
void resize(size_type sz, value_init_t);
void resize(size_type sz, default_init_t);
void push_back(value_init_t);
void push_back(default_init_t);
iterator insert(const_iterator position, size_type n, value_init_t);
iterator insert(const_iterator position, size_type n, default_init_t);</pre=
></blockquote></div></div></div><div class=3D"section" title=3D"Acknowledge=
ments"><div class=3D"titlepage"><div><div><h2 class=3D"title" style=3D"clea=
r: both"><a name=3D"d0e791"></a>Acknowledgements</h2></div></div></div><p>N=
evin ":-)" Liber, for pointing out the ambiguity issue with overloaded func=
tions, as
well as the allocator ramifications of the proposal.</p></div><=
div class=3D"section" title=3D"References"><div class=3D"titlepage"><div><d=
iv><h2 class=3D"title" style=3D"clear: both"><a name=3D"d0e796"></a>Referen=
ces</h2></div></div></div><div class=3D"itemizedlist"><ul class=3D"itemized=
list" type=3D"disc"><li class=3D"listitem"><p><a class=3D"link" href=3D"htt=
ps://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/QNHYTBcjAb4=
" target=3D"_top">More uniform initialization thread at isocpp.org</a></p><=
/li><li class=3D"listitem"><p><a class=3D"link" href=3D"https://groups.goog=
le.com/a/isocpp.org/forum/#!topic/std-proposals/4BHDIXgCcL8" target=3D"_top=
">Default initialization thread at isocpp.org</a></p></li><li class=3D"list=
item"><p><a class=3D"link" href=3D"https://groups.google.com/forum/#!topic/=
comp.std.c++/SuTRzR3S1mw" target=3D"_top">Request for std::vector and possi=
bly others: minimal initalization at
comp.std.c++</a></p></li></ul></div></div></div></b=
ody></html>
------=_Part_991_14525256.1356990329569--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Tue, 1 Jan 2013 08:55:34 -0800 (PST)
Raw View
------=_Part_1662_14754862.1357059334032
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Monday, December 31, 2012 1:49:21 AM UTC+4, Nicol Bolas wrote:
>
>
> This idea was ultimately extended into what became known as uniform=20
> initialization: one could initially any type via the use of a=20
> braced-init-list. Doing so provides a number of advantages,
>
Personally, I see only disadvantages. The initialization rules became too=
=20
complex and hard to understand. In spite of that horrible complexity, we=20
still don't have a lot of useful capabilities, that we might have if a more=
=20
rational alternative design was accepted.
In a perfect world, we would always use uniform initialization and never=20
> use direct constructor syntax.
>
In a perfect world uniform initialization / list-initialization would never=
=20
exist. In a perfect world braced-init-list would be a normal expression and=
=20
we might access its items as shown in the end this message.
This is all well and good, until we do this:
>
> std::vector<int> v1{20};
> std::vector<int> v2{int{}};
> std::vector<int> v3{int{}, int{}, int{}};
>
> v2 and v3 retain their old meaning. But v1 is now very different. It is=
=20
> an array containing a single element, the number 20. Why?
>
> Because uniform initialization syntax always prefers initializer list=20
> constructors if one is available that would fit the braced-init-list. Thi=
s=20
> is a consequence of uniform initialization syntax using the same syntax a=
s=20
> initializer lists: the braced-init-list. And since=20
> std::vector<int>::vector(std::initializer_list<int>) matches the=20
> braced-init-list ({20}), it will be preferred over=20
> std::vector<int>::vector(std::vector<int>::size_type)
>
> This is a problem because there is *no way* to get at the size_typeconstr=
uctor via uniform initialization.
>
I see your "problem" from the other side: why should I ever want to use
std::vector<int> v1{20};
instead of
std::vector<int> v(20);
in order to get 20 value-initialized elements?
There is no syntax that we can employ which will cause the conflicting=20
> initializer_list constructor to be ignored or to do anything else that=20
> would allow us to get at a different set of constructors.
>
If we want to get 20 value-initialized elements, then
std::vector<int> v(20);
does exactly what we want.
Now, this may seem like a rather unimportant issue. After all, if I know=20
> that I have to use constructor initialization with vector<int>, then I=20
> can simply do that. But consider code that is generic on the vector's=20
> type:
>
> template<typename T>
> std::vector<T> MakeVector()
> {
> return std::vector<T>{20};
> }
>
> By all rights, this code should always do the same thing: return a vector=
containing 20 value-initialized elements.
>
I would definitely prefer other behavior: it should _always_ create a=20
single element initialized with value 20 (unfortunately, this is not so=20
according to the current rules).
This is of much greater concern when dealing with more intricate templates.=
=20
> Consider the following trivial template function:
>
> template<typename T>
> T Process()
> {
> T t{};
> //do stuff with t;
> return T{t};
> }
>
> This function creates a temporary, does some processing, and returns a=20
> copy of it. This function requires that T be DefaultConstructible and=20
> CopyConstructible, in addition to whatever =93do stuff with t=94 requires=
..
>
This code can be rewritten as follows:
=20
template<typename T>
T Process()
{
T t{};
// do stuff with t;
return t;
}
=20
> The difference is that 13.3.1.7's list initialization overload resolution=
=20
> rules will behave differently. list-braced-init-list initialization will=
=20
> work exactly as it does. constr-braced-init-list will work opposite to th=
e=20
> current way. That is, it will check non-initializer_list constructors=20
> first, then go to the initializer_list ones if no matching constructors a=
re=20
> found.
>
What is the point in calling a constructor with multiple parameters by use=
=20
of a braced-init-list?
=20
Note that currently we are unable to
1) copy-initialize a base class subobject, or a non-static data member in a=
=20
mem-initializer-list, or an object created by a new-expression or by a=20
function-style type conversion,
2) direct-initialize objects returned by value from functions,
3) move items of the initializer-list,
4) handle items of unrelated types,
5) forward initializer-lists.
Alternative design might provide all these capabilities:
std::string s =3D "text";
auto &&li =3D { 1, std::move(s), "string" };
1) { 1, std::move(s), "string" } is a prvalue of type braced_init_list<int,=
=20
std::string, const char (&)[7]>
template <class... _Types>
class braced_init_list
{
public:
braced_init_list(_Types &&...params) :
__items(std::forward<_Types>(params)...) {}
braced_init_list(braced_init_list const &) =3D delete; //=20
non-copyable & non-movable
private:
__tuple<_Types &&> __items;
};
2) the lifetime of the temporary object designated by expression { 1,=20
std::move(s), "string" } (call it braced-init-list object) is the same as=
=20
the lifetime of the reference li (according to the usual rules for=20
reference-initialization).
3) Expressions 1, std::move(s) and "string" are used to initialize=20
references of types int &&, std::string && and const char (&)[7]=20
respectively. The reference of type int && is bound to a temporary object=
=20
whose lifetime is the same as the lifetime of the braced-init-list object.
4) Constructs
Type x{};
new Type{};
Type{};
perform value-initialization.
5) Constructs
Type x =3D y;
Type x{y};
new Type{y};
Type x{y};
perform copy-initialization.
6) Items of a braced-init-list object can be accessed through std::get:
template <class... _Items>
vector(braced_init_list<_Items...> &&__items)
requires(std::is_constructible<value_type, _Items>()...)
{
reserve(sizeof...(_Items));
__size =3D sizeof...(_Items);
auto *__p =3D data();
(__create_item_at(__p, std::get<enum(_Items)>(__items)), ++__p) ...=
;
// enum(_Items) expands to 0, 1, 2, ..., (sizeof...(_Items) - 1)
}
explicit vector(size_type);
Examples:
std::vector<int> v1(20); // should create 20 value-initialized elements
std::vector<int> v2{20}; // should be equivalent to std::vector<int> v2=
=20
=3D 20; (ill-formed)
std::vector<int> v3({20}); // should create one element initialized=20
with value 20
std::vector<int> v4 =3D {20}; // should create one element initialized=
=20
with value 20
std::vector<int> v5{10, 20}; // should be ill-formed
std::vector<int> v6({10, 20}); // should create two elements=20
initialized with values 10 and 20
std::vector<int> v7 =3D {10, 20}; // should create two elements=20
initialized with values 10 and 20
void f(std::vector<int> const &v);
std::vector<int> g(bool b)
{
f({20}); // should create one element initialized with value 20
std::vector<int>{}; // should create value-initialized container
std::vector<int>{20}; // should be ill-formed copy-initialization=
=20
of std::vector<int> with 20
std::vector<int>({20}); // should create one element initialized=20
with value 20=20
if (b)
return {20}; // should create one element initialized with=20
value 20
return explicit(20); // should create 20 value-initialized elements
}
template <class... _Types>
class tuple
{
explicit tuple(_Types const &...);
template <class... _UTypes>
explicit tuple(_UTypes &&...);
// non-explicit
template <class... _UTypes>
tuple(braced_init_list<_Items...> &&__items)
requires(std::is_constructible<_Types, _Items>()...) :
tuple(std::get<enum(_Items)>(__items)...) {}
....
};
struct X {};
void f1(tuple<int, int> const &);
void f2(vector<X> const &);
void f3(braced_init_list<char, char, char> &&li)
{
f1({0, 0}); // should be well-formed (in contrast to very strange=
=20
C++11 behavior)
f2({10, X()}); // should be ill-formed (in contrast to very strange=
=20
C++11 behavior)
char arr1[] =3D li; // should be well-formed
char arr2[3] =3D li; // should be well-formed
struct A
{
char arr[4];
} a =3D {li}; // should be well-formed
char (arr3[]){'a', 'b'}; // should be ill-formed
char (arr4[])({'a', 'b'}); // should be well-formed
}
It's too late to do right things now, though.
--=20
------=_Part_1662_14754862.1357059334032
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Monday, December 31, 2012 1:49:21 AM UTC+4, Nicol Bolas wrote:<blockquot=
e class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: =
1px #ccc solid;padding-left: 1ex;"><div title=3D"Introduction"><br><p>This =
idea was ultimately extended into what became known as uniform initializati=
on:
one could initially any type via the use of a braced-init-list.=
Doing so provides a
number of advantages,</p></div></blockquote><div>Personally, I =
see only disadvantages. The initialization rules became too complex and har=
d to understand. In spite of that horrible complexity, we still don't have =
a lot of useful capabilities, that we might have if a more rational alterna=
tive design was accepted.<br><br></div><blockquote class=3D"gmail_quote" st=
yle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-lef=
t: 1ex;"><div title=3D"Introduction"><p> In a perfect world, we would alway=
s use uniform initialization
and never use direct constructor syntax.</p></div></blockquote>=
<div>In a perfect world uniform initialization / list-initialization would =
never exist. In a perfect world braced-init-list would be a normal expressi=
on and we might access its items as shown in the end this message.<br><br><=
/div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;"><div title=3D"Motivation =
and Scope"><p>This is all well and good, until we do this:</p><pre>std::vec=
tor<int> v1{20};
std::vector<int> v2{int{}};
std::vector<int> v3{int{}, int{}, int{}};</pre><p><code>v2</code> and=
<code>v3</code> retain their old meaning. But
<code>v1</code> is now very different. It is an array conta=
ining a single
element, the number 20. Why?</p><p>Because uniform initializati=
on syntax always prefers initializer list constructors if
one is available that would fit the braced-init-list. This is a=
consequence of uniform
initialization syntax using the same syntax as initializer list=
s: the braced-init-list.
And since
<code>std::vector<int>::vector(std::<wbr>initializer_=
list<int>)</code>
matches the braced-init-list (<code>{20}</code>), it will be pr=
eferred over
<code>std::vector<int>::vector(std::<wbr>vector<in=
t>::size_type)</code></p><p>This is a problem because there is <span><i>=
no way</i></span> to get at the
<span>size_type</span> constructor via uniform initializati=
on.</p></div></blockquote><div>I see your "problem" from the other side: wh=
y should I ever want to use<br><br><pre> std::vector<int> v1{20};<b=
r><br>instead of<br><br> std::vector<int> v(20);<br><br>in order to=
get 20 value-initialized elements?<br></pre><br></div><blockquote class=3D=
"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc s=
olid;padding-left: 1ex;"><div title=3D"Motivation and Scope"><p> There is n=
o syntax
that we can employ which will cause the conflicting <span>initi=
alizer_list</span>
constructor to be ignored or to do anything else that would all=
ow us to get at a
different set of constructors.</p></div></blockquote><div>If we=
want to get 20 value-initialized elements, then<br><br><pre> std::vector=
<int> v(20);<br><br></pre> does exactly what we want.<br><br></d=
iv><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;"><div title=3D"Motivation an=
d Scope"><p>Now, this may seem like a rather unimportant issue. After all, =
if I know that I have
to use constructor initialization with <span>vector<int><=
/span>, then I can simply do
that. But consider code that is generic on the <span>vector</sp=
an>'s type:</p><pre>template<typename T>
std::vector<T> MakeVector()
{
return std::vector<T>{20};
}</pre><p>By all rights, this code should always do the same thing: return =
a <span>vector</span>
containing 20 value-initialized elements.</p></div></blockquote=
><div>I would definitely prefer other behavior: it should _always_ create =
a single element initialized with value 20 (unfortunately, this is not so a=
ccording to the current rules).<br><br></div><blockquote class=3D"gmail_quo=
te" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddi=
ng-left: 1ex;"><div title=3D"Motivation and Scope"><p>This is of much great=
er concern when dealing with more intricate templates. Consider
the following trivial template function:</p><pre>template<ty=
pename T>
T Process()
{
T t{};
//do stuff with t;
return T{t};
}</pre><p>This function creates a temporary, does some processing, and retu=
rns a copy of it.
This function requires that <span>T</span> be DefaultConstructi=
ble and
CopyConstructible, in addition to whatever <span>=93<span>do st=
uff with t</span>=94</span>
requires.</p></div></blockquote><div>This code can be rewritten=
as follows:<br> </div><div> template<typename T&=
gt;<br> T Process()<br> {<br> &nbs=
p; T t{};<br> &n=
bsp; // do stuff with t;<br>  =
; return t;<br> }<br> </div><blockquote class=3D"gma=
il_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid=
;padding-left: 1ex;"><div title=3D"Design Overview"><p>The difference is th=
at 13.3.1.7's list initialization overload resolution rules will
behave differently. list-braced-init-list initialization will w=
ork exactly as it does.
constr-braced-init-list will work opposite to the current way. =
That is, it will check
non-initializer_list constructors first, then go to the initial=
izer_list ones if no
matching constructors are found.</p></div></blockquote><div>Wha=
t is the point in calling a constructor with multiple parameters by use of =
a braced-init-list?<br> <br>Note that currently we are unable to<br>1)=
copy-initialize a base class subobject, or a non-static data member in a m=
em-initializer-list, or an object created by a new-expression or by a funct=
ion-style type conversion,<br>2) direct-initialize objects returned by valu=
e from functions,<br>3) move items of the initializer-list,<br>4) handle it=
ems of unrelated types,<br>5) forward initializer-lists.<br><br>Alternative=
design might provide all these capabilities:<br><br> std=
::string s =3D "text";<br> auto &&li =3D { 1, std=
::move(s), "string" };<br><br>1) { 1, std::move(s), "string" } is a prvalue=
of type braced_init_list<int, std::string, const char (&)[7]><br=
><br> template <class... _Types><br> &nb=
sp; class braced_init_list<br> {<=
br> public:<br> =
braced_init_list(_Types &&...params) :<br> =
__items(std::forward<_Types&g=
t;(params)...) {}<br> braced_init=
_list(braced_init_list const &) =3D delete; // non-copyable & non-m=
ovable<br> private:<br> &nbs=
p; __tuple<_Types &&> __items;<br> };=
<br><br>2) the lifetime of the temporary object designated by expression { =
1, std::move(s), "string" } (call it braced-init-list object) is the same a=
s the lifetime of the reference li (according to the usual rules for refere=
nce-initialization).<br><br>3) Expressions 1, std::move(s) and "string" are=
used to initialize references of types int &&, std::string &&a=
mp; and const char (&)[7] respectively. The reference of type int &=
& is bound to a temporary object whose lifetime is the same as the life=
time of the braced-init-list object.<br><br>4) Constructs<br><br> &nbs=
p; Type x{};<br> new Type{};<br> =
Type{};<br><br>perform value-initialization.<br><br>5) Constructs<br><br>&n=
bsp; Type x =3D y;<br> Type x{y};<br> &n=
bsp; new Type{y};<br> Type x{y};<br><br>perform cop=
y-initialization.<br><br>6) Items of a braced-init-list object can be acces=
sed through std::get:<br><br> template <class... _Item=
s><br> vector(braced_init_list=
<_Items...> &&__items)<br>  =
; requires(std::is_constructible<value_typ=
e, _Items>()...)<br> {<br> &nbs=
p; reserve(sizeof...(_Items));<br>  =
; __size =3D sizeof...(_Items);<br> &nbs=
p; auto *__p =3D data();<br>  =
; (__create_item_at(__p, std::get<enum(_Items)>(__items)), ++__=
p) ...;<br> // enum(_Items) expan=
ds to 0, 1, 2, ..., (sizeof...(_Items) - 1)<br> }<br><br>=
explicit vector(size_type);<br><br>Examples:<br><br>&nbs=
p; std::vector<int> v1(20); // should create 20 value-ini=
tialized elements<br> std::vector<int> v2{20}; // s=
hould be equivalent to std::vector<int> v2 =3D 20; (ill-formed)<br>&n=
bsp; std::vector<int> v3({20}); // should create one elem=
ent initialized with value 20<br> std::vector<int> =
v4 =3D {20}; // should create one element initialized with value 20<br>&nbs=
p; std::vector<int> v5{10, 20}; // should be ill-formed<b=
r> std::vector<int> v6({10, 20}); // should create =
two elements initialized with values 10 and 20<br> std::v=
ector<int> v7 =3D {10, 20}; // should create two elements initialized=
with values 10 and 20<br><br> void f(std::vector<int&=
gt; const &v);<br> std::vector<int> g(bool b)<b=
r> {<br> f({20}=
); // should create one element initialized with value 20<br><br> &nbs=
p; std::vector<int>{}; // should create=
value-initialized container<br> =
std::vector<int>{20}; // should be ill-formed copy-initialization of =
std::vector<int> with 20<br>  =
; std::vector<int>({20}); // should create one element initialized wi=
th value 20 <br><br> if (b)<br>&n=
bsp; return {20=
}; // should create one element initialized with value 20<br> &n=
bsp; return explicit(20); // should create 20 value=
-initialized elements<br> }<br><br> tem=
plate <class... _Types><br> =
class tuple<br> {<br>  =
; explicit tuple(_Types const &...);<br> &=
nbsp; template <class... _UTypes><br> &n=
bsp; explicit tuple(_UTypes &=
&...);<br><br> // non-explici=
t<br> template <class... _UTyp=
es><br>  =
; tuple(braced_init_list<_Items...> &&__items)<br>  =
; &n=
bsp; requires(std::is_constructible<_Types, _Items>()...) :<br> =
&nb=
sp; tuple(std::get<enum(_Items)>(__item=
s)...) {}<br> ....<br>  =
; };<br><br> struct X {};<br><br> =
void f1(tuple<int, int> const &);<br> void f2(=
vector<X> const &);<br><br> void f3(braced_init=
_list<char, char, char> &&li)<br> {<br>&nbs=
p; f1({0, 0}); // should be well-formed=
(in contrast to very strange C++11 behavior)<br> &n=
bsp; f2({10, X()}); // should be ill-formed (in contrast to ver=
y strange C++11 behavior)<br><br> =
char arr1[] =3D li; // should be well-formed<br> &n=
bsp; char arr2[3] =3D li; // should be well-formed<br><br> =
; struct A<br> &=
nbsp; {<br> &nbs=
p; char arr[4];<br> }=
a =3D {li}; // should be well-formed<br><br> =
char (arr3[]){'a', 'b'}; // should be ill-formed<br> &nbs=
p; char (arr4[])({'a', 'b'}); // should be we=
ll-formed<br> }<br><br>It's too late to do right things n=
ow, though.<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1662_14754862.1357059334032--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 1 Jan 2013 13:30:50 -0800 (PST)
Raw View
------=_Part_1486_26923364.1357075850199
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Tuesday, January 1, 2013 8:55:34 AM UTC-8, Nikolay Ivchenkov wrote:
>
> On Monday, December 31, 2012 1:49:21 AM UTC+4, Nicol Bolas wrote:
>>
>>
>> This idea was ultimately extended into what became known as uniform=20
>> initialization: one could initially any type via the use of a=20
>> braced-init-list. Doing so provides a number of advantages,
>>
> Personally, I see only disadvantages. The initialization rules became too=
=20
> complex and hard to understand. In spite of that horrible complexity, we=
=20
> still don't have a lot of useful capabilities, that we might have if a mo=
re=20
> rational alternative design was accepted.
>
But they're not complex; the rules are quite simple. The only complex part=
=20
is the whole initializer_list issue. Which again, this is intended to solve=
..
This is all well and good, until we do this:
>>
>> std::vector<int> v1{20};
>> std::vector<int> v2{int{}};
>> std::vector<int> v3{int{}, int{}, int{}};
>>
>> v2 and v3 retain their old meaning. But v1 is now very different. It is=
=20
>> an array containing a single element, the number 20. Why?
>>
>> Because uniform initialization syntax always prefers initializer list=20
>> constructors if one is available that would fit the braced-init-list. Th=
is=20
>> is a consequence of uniform initialization syntax using the same syntax =
as=20
>> initializer lists: the braced-init-list. And since=20
>> std::vector<int>::vector(std::initializer_list<int>) matches the=20
>> braced-init-list ({20}), it will be preferred over=20
>> std::vector<int>::vector(std::vector<int>::size_type)
>>
>> This is a problem because there is *no way* to get at the size_typeconst=
ructor via uniform initialization.
>>
> I see your "problem" from the other side: why should I ever want to use
>
> std::vector<int> v1{20};
>
> instead of
>
> std::vector<int> v(20);
>
> in order to get 20 value-initialized elements?
>
>
Because it always works the same way, regardless of whether 20 is a literal=
=20
or `int()` (which causes the most vexing parse. Admittedly not useful, but=
=20
I don't have to change my syntax just for that).
=20
> There is no syntax that we can employ which will cause the conflicting=20
>> initializer_list constructor to be ignored or to do anything else that=
=20
>> would allow us to get at a different set of constructors.
>>
> If we want to get 20 value-initialized elements, then
>
> std::vector<int> v(20);
>
> does exactly what we want.
>
That's not using uniform initialization syntax. The point of which is to *
always* use {}; just read Stroustrup's C++ tour on the website<http://isocp=
p.org/tour>,=20
where he advocates *always* using {}.
Now, this may seem like a rather unimportant issue. After all, if I know=20
>> that I have to use constructor initialization with vector<int>, then I=
=20
>> can simply do that. But consider code that is generic on the vector's=20
>> type:
>>
>> template<typename T>
>> std::vector<T> MakeVector()
>> {
>> return std::vector<T>{20};
>> }
>>
>> By all rights, this code should always do the same thing: return a vecto=
rcontaining 20 value-initialized elements.
>>
> I would definitely prefer other behavior: it should _always_ create a=20
> single element initialized with value 20 (unfortunately, this is not so=
=20
> according to the current rules).
>
But if you want that behavior you can guarantee it by doing this:
return std::vector<T>{{20}};
There's no way to do the opposite: guarantee that you're calling the=20
constructor.
=20
>
> This is of much greater concern when dealing with more intricate=20
>> templates. Consider the following trivial template function:
>>
>> template<typename T>
>> T Process()
>> {
>> T t{};
>> //do stuff with t;
>> return T{t};
>> }
>>
>> This function creates a temporary, does some processing, and returns a=
=20
>> copy of it. This function requires that T be DefaultConstructible and=20
>> CopyConstructible, in addition to whatever =93do stuff with t=94 require=
s.
>>
> This code can be rewritten as follows:
> =20
> template<typename T>
> T Process()
> {
> T t{};
> // do stuff with t;
> return t;
> }
>
Yes, but then it wouldn't be an example of the problem. It's an *example*,=
=20
something that demonstrates the issue.
=20
> The difference is that 13.3.1.7's list initialization overload resolution=
=20
>> rules will behave differently. list-braced-init-list initialization will=
=20
>> work exactly as it does. constr-braced-init-list will work opposite to t=
he=20
>> current way. That is, it will check non-initializer_list constructors=20
>> first, then go to the initializer_list ones if no matching constructors =
are=20
>> found.
>>
> What is the point in calling a constructor with multiple parameters by us=
e=20
> of a braced-init-list?
>
This:
std::string GetLuaString()
{
size_t len =3D 0;
const char *str =3D lua_tolstring(L, -1, &len);
{len, str}; //No need to type std::string here.
}
This is one of the nice things that uniform initialization gives is: it=20
allows us to create things without pointlessly naming the type again.
=20
> Note that currently we are unable to
> 1) copy-initialize a base class subobject, or a non-static data member in=
=20
> a mem-initializer-list, or an object created by a new-expression or by a=
=20
> function-style type conversion,
>
Why would you *ever* want to copy-initialize any of those? Copy=20
initialization is a functional subset of direct initialization. Anything=20
you could do with copy initialization you can do with direct initialization=
..
Oh, and one of the purposes of uniform initialization is so that you don't=
=20
have to know the difference between direct and copy initialization.=20
Granted, they reneged on that by making copy-list-initialization not use=20
explicit constructors, but there's a point to that difference.
2) direct-initialize objects returned by value from functions,
> 3) move items of the initializer-list,
>
Of course not. Those items may be statically allocated.
=20
> 4) handle items of unrelated types,
>
5) forward initializer-lists.
>
.... What does that have to do with anything being discussed here?
=20
> Alternative design might provide all these capabilities:
>
> std::string s =3D "text";
> auto &&li =3D { 1, std::move(s), "string" };
>
What you want is something we already have. It's called a *tuple*. You can=
=20
construct them from arbitrary arguments via make_tuple. If you want to=20
forward things as a tuple, you use forward_as_tuple.
=20
> 2) the lifetime of the temporary object designated by expression { 1,=20
> std::move(s), "string" } (call it braced-init-list object) is the same as=
=20
> the lifetime of the reference li (according to the usual rules for=20
> reference-initialization).
>
Yeah, that doesn't work. If braced-init-list is an object, it's members *
cannot* extend the lifetime of temporary parameters that are passed to the=
=20
constructor of that object. The constructor's argument will bind to the=20
temporary *first*, and thus the lifetime will be the lifetime of the=20
constructor argument, not the object itself. So that can't work.
3) Expressions 1, std::move(s) and "string" are used to initialize=20
> references of types int &&, std::string && and const char (&)[7]=20
> respectively. The reference of type int && is bound to a temporary object=
=20
> whose lifetime is the same as the lifetime of the braced-init-list object=
..
>
> 4) Constructs
>
> Type x{};
> new Type{};
> Type{};
>
> perform value-initialization.
>
> 5) Constructs
>
> Type x =3D y;
> Type x{y};
> new Type{y};
> Type x{y};
>
> perform copy-initialization.
>
So basically, you're saying that list-initialization should have been=20
defined in terms of copy initialization instead of direct initialization.=
=20
That's *horrible*; why would we ever want that? What's to be gained by it *=
at=20
all?*
The *entire point* of "uniform initialization" is that it is *uniformly*use=
d to initialize=20
*everything*. You cannot copy-initialize every object you would ever want=
=20
to create. You're going to have to use direct initialization. So if you're=
=20
going to create a uniform initialization syntax, in order for it to be used=
=20
*everywhere*, it must use direct constructor initialization.
It's too late to do right things now, though.
>
Thank goodness, because this is as far from "right things" as it gets.
--=20
------=_Part_1486_26923364.1357075850199
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Tuesday, January 1, 2013 8:55:34 AM UTC-8, Nikolay Ivchenkov wrote:<bloc=
kquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-l=
eft: 1px #ccc solid;padding-left: 1ex;">On Monday, December 31, 2012 1:49:2=
1 AM UTC+4, Nicol Bolas wrote:<blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div =
title=3D"Introduction"><br><p>This idea was ultimately extended into what b=
ecame known as uniform initialization:
one could initially any type via the use of a braced-init-list.=
Doing so provides a
number of advantages,</p></div></blockquote><div>Personally, I =
see only disadvantages. The initialization rules became too complex and har=
d to understand. In spite of that horrible complexity, we still don't have =
a lot of useful capabilities, that we might have if a more rational alterna=
tive design was accepted.<br></div></blockquote><div><br>But they're not co=
mplex; the rules are quite simple. The only complex part is the whole initi=
alizer_list issue. Which again, this is intended to solve.<br><br></div><bl=
ockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border=
-left: 1px #ccc solid;padding-left: 1ex;"><div></div><blockquote class=3D"g=
mail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;=
padding-left:1ex"><div title=3D"Motivation and Scope"><p>This is all well a=
nd good, until we do this:</p><pre>std::vector<int> v1{20};
std::vector<int> v2{int{}};
std::vector<int> v3{int{}, int{}, int{}};</pre><p><code>v2</code> and=
<code>v3</code> retain their old meaning. But
<code>v1</code> is now very different. It is an array conta=
ining a single
element, the number 20. Why?</p><p>Because uniform initializati=
on syntax always prefers initializer list constructors if
one is available that would fit the braced-init-list. This is a=
consequence of uniform
initialization syntax using the same syntax as initializer list=
s: the braced-init-list.
And since
<code>std::vector<int>::vector(std::<wbr>initializer_=
list<int>)</code>
matches the braced-init-list (<code>{20}</code>), it will be pr=
eferred over
<code>std::vector<int>::vector(std::<wbr>vector<in=
t>::size_type)</code></p><p>This is a problem because there is <span><i>=
no way</i></span> to get at the
<span>size_type</span> constructor via uniform initializati=
on.</p></div></blockquote><div>I see your "problem" from the other side: wh=
y should I ever want to use<br><br><pre> std::vector<int> v1{20};<b=
r><br>instead of<br><br> std::vector<int> v(20);<br><br>in order to=
get 20 value-initialized elements?<br></pre></div></blockquote><div><br>Be=
cause it always works the same way, regardless of whether 20 is a literal o=
r `int()` (which causes the most vexing parse. Admittedly not useful, but I=
don't have to change my syntax just for that).<br> </div><blockquote =
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1p=
x #ccc solid;padding-left: 1ex;"><div></div><blockquote class=3D"gmail_quot=
e" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-l=
eft:1ex"><div title=3D"Motivation and Scope"><p> There is no syntax
that we can employ which will cause the conflicting <span>initi=
alizer_list</span>
constructor to be ignored or to do anything else that would all=
ow us to get at a
different set of constructors.</p></div></blockquote><div>If we=
want to get 20 value-initialized elements, then<br><br><pre> std::vector=
<int> v(20);<br><br></pre> does exactly what we want.<br></div><=
/blockquote><div><br>That's not using uniform initialization syntax. The po=
int of which is to <i>always</i> use {}; just read <a href=3D"http://isocpp=
..org/tour">Stroustrup's C++ tour on the website</a>, where he advocates <i>=
always</i> using {}.<br><br></div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;"><div></div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin=
-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div title=3D"Moti=
vation and Scope"><p>Now, this may seem like a rather unimportant issue. Af=
ter all, if I know that I have
to use constructor initialization with <span>vector<int><=
/span>, then I can simply do
that. But consider code that is generic on the <span>vector</sp=
an>'s type:</p><pre>template<typename T>
std::vector<T> MakeVector()
{
return std::vector<T>{20};
}</pre><p>By all rights, this code should always do the same thing: return =
a <span>vector</span>
containing 20 value-initialized elements.</p></div></blockquote=
><div>I would definitely prefer other behavior: it should _always_ create =
a single element initialized with value 20 (unfortunately, this is not so a=
ccording to the current rules).<br></div></blockquote><div><br>But if you w=
ant that behavior you can guarantee it by doing this:<br><br><div class=3D"=
prettyprint" style=3D"background-color: rgb(250, 250, 250); border-color: r=
gb(187, 187, 187); border-style: solid; border-width: 1px; word-wrap: break=
-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">return</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> std</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify">vector</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify"><</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">T</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">>{{</span><span style=3D"color: #066;" class=3D"styled-by=
-prettify">20</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">}};</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
</span></div></code></div><br>There's no way to do the opposite: guarantee =
that you're calling the constructor.<br> </div><blockquote class=3D"gm=
ail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc soli=
d;padding-left: 1ex;"><div><br></div><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex=
"><div title=3D"Motivation and Scope"><p>This is of much greater concern wh=
en dealing with more intricate templates. Consider
the following trivial template function:</p><pre>template<ty=
pename T>
T Process()
{
T t{};
//do stuff with t;
return T{t};
}</pre><p>This function creates a temporary, does some processing, and retu=
rns a copy of it.
This function requires that <span>T</span> be DefaultConstructi=
ble and
CopyConstructible, in addition to whatever <span>=93<span>do st=
uff with t</span>=94</span>
requires.</p></div></blockquote><div>This code can be rewritten=
as follows:<br> </div><div> template<typename T&=
gt;<br> T Process()<br> {<br> &nbs=
p; T t{};<br> &n=
bsp; // do stuff with t;<br>  =
; return t;<br> }<br></div></blockquote><div><br>Yes, but=
then it wouldn't be an example of the problem. It's an <i>example</i>, som=
ething that demonstrates the issue.<br> <br></div><blockquote class=3D=
"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc s=
olid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"margin:=
0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div title=
=3D"Design Overview"><p>The difference is that 13.3.1.7's list initializati=
on overload resolution rules will
behave differently. list-braced-init-list initialization will w=
ork exactly as it does.
constr-braced-init-list will work opposite to the current way. =
That is, it will check
non-initializer_list constructors first, then go to the initial=
izer_list ones if no
matching constructors are found.</p></div></blockquote><div>Wha=
t is the point in calling a constructor with multiple parameters by use of =
a braced-init-list?<br></div></blockquote><div><br>This:<br><br><div class=
=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border-colo=
r: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wrap: b=
reak-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span=
style=3D"color: #000;" class=3D"styled-by-prettify">std</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"colo=
r: #008;" class=3D"styled-by-prettify">string</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #606;" cla=
ss=3D"styled-by-prettify">GetLuaString</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">()</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"><br> size_t len </span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify"=
>0</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"><br> </span=
><span style=3D"color: #008;" class=3D"styled-by-prettify">const</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">char</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">*</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">str </span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> lua_tolstring</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify">L</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">-</span><span style=
=3D"color: #066;" class=3D"styled-by-prettify">1</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">&</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">len</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
<br> </span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>{</span><span style=3D"color: #000;" class=3D"styled-by-prettify">len</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> str</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">};</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #800;"=
class=3D"styled-by-prettify">//No need to type std::string here.</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">}</span></div></code></div=
><br>This is one of the nice things that uniform initialization gives is: i=
t allows us to create things without pointlessly naming the type again.<br>=
</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div> Note th=
at currently we are unable to<br>1) copy-initialize a base class subobject,=
or a non-static data member in a mem-initializer-list, or an object create=
d by a new-expression or by a function-style type conversion,<br></div></bl=
ockquote><div><br>Why would you <i>ever</i> want to copy-initialize any of =
those? Copy initialization is a functional subset of direct initialization.=
Anything you could do with copy initialization you can do with direct init=
ialization.<br><br>Oh, and one of the purposes of uniform initialization is=
so that you don't have to know the difference between direct and copy init=
ialization. Granted, they reneged on that by making copy-list-initializatio=
n not use explicit constructors, but there's a point to that difference.<br=
><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left=
: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>2) direct-init=
ialize objects returned by value from functions,<br>3) move items of the in=
itializer-list,<br></div></blockquote><div><br>Of course not. Those items m=
ay be statically allocated.<br> </div><blockquote class=3D"gmail_quote=
" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding=
-left: 1ex;"><div>4) handle items of unrelated types,</div></blockquote><bl=
ockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border=
-left: 1px #ccc solid;padding-left: 1ex;"><div>5) forward initializer-lists=
..<br></div></blockquote><div><br>... What does that have to do with anythin=
g being discussed here?<br> </div><blockquote class=3D"gmail_quote" st=
yle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-lef=
t: 1ex;"><div>Alternative design might provide all these capabilities:<br><=
/div></blockquote><div></div><blockquote class=3D"gmail_quote" style=3D"mar=
gin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><=
div><br> std::string s =3D "text";<br> =
auto &&li =3D { 1, std::move(s), "string" };<br></div></blockquote>=
<div><br>What you want is something we already have. It's called a <i>tuple=
</i>. You can construct them from arbitrary arguments via make_tuple. If yo=
u want to forward things as a tuple, you use forward_as_tuple.<br> </d=
iv><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;"><div>2) the lifetime of the=
temporary object designated by expression { 1, std::move(s), "string" } (c=
all it braced-init-list object) is the same as the lifetime of the referenc=
e li (according to the usual rules for reference-initialization).<br></div>=
</blockquote><div><br>Yeah, that doesn't work. If braced-init-list is an ob=
ject, it's members <i>cannot</i> extend the lifetime of temporary parameter=
s that are passed to the constructor of that object. The constructor's argu=
ment will bind to the temporary <i>first</i>, and thus the lifetime will be=
the lifetime of the constructor argument, not the object itself. So that c=
an't work.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: =
0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>3=
) Expressions 1, std::move(s) and "string" are used to initialize reference=
s of types int &&, std::string && and const char (&)[7]=
respectively. The reference of type int && is bound to a temporary=
object whose lifetime is the same as the lifetime of the braced-init-list =
object.<br><br>4) Constructs<br><br> Type x{};<br> &=
nbsp; new Type{};<br> Type{};<br><br>perform value-=
initialization.<br><br>5) Constructs<br><br> Type x =3D y=
;<br> Type x{y};<br> new Type{y};<br>&n=
bsp; Type x{y};<br><br>perform copy-initialization.<br></div></=
blockquote><div><br>So basically, you're saying that list-initialization sh=
ould have been defined in terms of copy initialization instead of direct in=
itialization. That's <i>horrible</i>; why would we ever want that? What's t=
o be gained by it <i>at all?</i><br><br>The <i>entire point</i> of "uniform=
initialization" is that it is <i>uniformly</i> used to initialize <i>every=
thing</i>. You cannot copy-initialize every object you would ever want to c=
reate. You're going to have to use direct initialization. So if you're goin=
g to create a uniform initialization syntax, in order for it to be used <i>=
everywhere</i>, it must use direct constructor initialization.<br></div><br=
><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bo=
rder-left: 1px #ccc solid;padding-left: 1ex;"><div>It's too late to do righ=
t things now, though.<br></div></blockquote><div><br>Thank goodness, becaus=
e this is as far from "right things" as it gets.<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1486_26923364.1357075850199--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Wed, 2 Jan 2013 07:10:06 -0800 (PST)
Raw View
------=_Part_11_32838542.1357139406815
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Wednesday, January 2, 2013 1:30:50 AM UTC+4, Nicol Bolas wrote:
>
> On Tuesday, January 1, 2013 8:55:34 AM UTC-8, Nikolay Ivchenkov wrote:
>>
>> On Monday, December 31, 2012 1:49:21 AM UTC+4, Nicol Bolas wrote:
>>>
>>>
>>> This idea was ultimately extended into what became known as uniform=20
>>> initialization: one could initially any type via the use of a=20
>>> braced-init-list. Doing so provides a number of advantages,
>>>
>> Personally, I see only disadvantages. The initialization rules became to=
o=20
>> complex and hard to understand. In spite of that horrible complexity, we=
=20
>> still don't have a lot of useful capabilities, that we might have if a m=
ore=20
>> rational alternative design was accepted.
>>
>
> But they're not complex; the rules are quite simple.
>
IMO, they are neither simple nor intuitive, especially with regard to=20
overload resolution.
=20
> I see your "problem" from the other side: why should I ever want to use
>>
>> std::vector<int> v1{20};
>>
>> instead of
>>
>> std::vector<int> v(20);
>>
>> in order to get 20 value-initialized elements?
>>
>>
> Because it always works the same way, regardless of whether 20 is a=20
> literal or `int()` (which causes the most vexing parse. Admittedly not=20
> useful, but I don't have to change my syntax just for that).
>
That's too weak argument, I can just replace int() with int{} or 0. Note=20
that when you want to pass a value-initialized temporary as a template=20
argument, you can't use int() anyway, because it would be treated as a=20
function type.
The downside of "almighty" initialization is weak compile-time checking,=20
this is much more important factor for me:
int n =3D 20;
int *p =3D &n;
std::vector<int *> v{p};
Suppose that here I wanted to create *p value-initialized pointers, but I=
=20
forgot to dereference p. The mistake will not be diagnosed.
If we want to get 20 value-initialized elements, then
>>
>> std::vector<int> v(20);
>>
>> does exactly what we want.
>>
>
> That's not using uniform initialization syntax. The point of which is to =
*
> always* use {}; just read Stroustrup's C++ tour on the website<http://iso=
cpp.org/tour>,=20
> where he advocates *always* using {}.
>
I don't see point there, his argumentation is neither convincing nor even=
=20
plausible for me.
Now, this may seem like a rather unimportant issue. After all, if I know=20
>>> that I have to use constructor initialization with vector<int>, then I=
=20
>>> can simply do that. But consider code that is generic on the vector's=
=20
>>> type:
>>>
>>> template<typename T>
>>> std::vector<T> MakeVector()
>>> {
>>> return std::vector<T>{20};
>>> }
>>>
>>> By all rights, this code should always do the same thing: return a=20
>>> vector containing 20 value-initialized elements.
>>>
>> I would definitely prefer other behavior: it should _always_ create a=20
>> single element initialized with value 20 (unfortunately, this is not so=
=20
>> according to the current rules).
>>
>
> But if you want that behavior you can guarantee it by doing this:
>
> return std::vector<T>{{20}};
>
Actually, such "almighty" initialization is unsafe again:
#include <iostream>
#include <vector>
int main()
{
for (auto &x : std::vector<int *>{{20}})
std::cout << x << std::endl;
}
Here the container will have 20 value-initialized pointers, while I would=
=20
prefer a compile-time error.
=20
> There's no way to do the opposite: guarantee that you're calling the=20
> constructor.
>
Well, something like this
explicit<T>(expr_list) // expression of type T
that would perform only direct-initialization exactly as in
T t(expr_list);
and (unlike to function-style type conversions) would be unable to perform=
=20
additional conversions that can be done via static_cast, reinterpret_cast=
=20
and const_cast, could solve the problem.
This is of much greater concern when dealing with more intricate templates.=
=20
>>> Consider the following trivial template function:
>>>
>>> template<typename T>
>>> T Process()
>>> {
>>> T t{};
>>> //do stuff with t;
>>> return T{t};
>>> }
>>>
>>> This function creates a temporary, does some processing, and returns a=
=20
>>> copy of it. This function requires that T be DefaultConstructible and=
=20
>>> CopyConstructible, in addition to whatever =93do stuff with t=94 requir=
es.
>>>
>> This code can be rewritten as follows:
>> =20
>> template<typename T>
>> T Process()
>> {
>> T t{};
>> // do stuff with t;
>> return t;
>> }
>>
>
> Yes, but then it wouldn't be an example of the problem. It's an *example*=
,=20
> something that demonstrates the issue.
>
There is an open core issue about this:=20
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1467
Probably, the rules will be changed according to the suggestion published=
=20
there.
=20
> The difference is that 13.3.1.7's list initialization overload resolution=
=20
>>> rules will behave differently. list-braced-init-list initialization wil=
l=20
>>> work exactly as it does. constr-braced-init-list will work opposite to =
the=20
>>> current way. That is, it will check non-initializer_list constructors=
=20
>>> first, then go to the initializer_list ones if no matching constructors=
are=20
>>> found.
>>>
>> What is the point in calling a constructor with multiple parameters by=
=20
>> use of a braced-init-list?
>>
>
> This:
>
> std::string GetLuaString()
> {
> size_t len =3D 0;
> const char *str =3D lua_tolstring(L, -1, &len);
> {len, str}; //No need to type std::string here.
> }
>
> This is one of the nice things that uniform initialization gives is: it=
=20
> allows us to create things without pointlessly naming the type again.
>
So, if we don't have a convenient syntax for ()-style direct-initialization=
=20
of returned objects, then instead of introducing such a useful thing into=
=20
the language we need to invent a different kind initialization? Sorry, I=20
don't see the point.
What is the conceptual difference between copy-initialization and=20
direct-initialization? Copy-initialization is used for relatively safe=20
initialization of one entity by other entity with similar semantics and=20
value. Direct-initialization is used in the rest of cases. When items of=20
one tuple-like entity are copy-initialized by the respective items of=20
another tuple-like entity, the sequence of such initializations can=20
reasonably be treated as a copy-initialization:
std::vector<int> v =3D {1, 2, 3};
In C++03 brace-enclosed initializer lists were used as tuple-like entities=
=20
for initialization of aggregates which can also be interpreted as=20
tuple-like entities. In C++11 we can implicitly (and suddenly) convert a=20
tuple-like entity to an object with entirely different semantics.
()-style direct-initialization gives me ability to express the intention=20
that comma-separated items should be interpreted as constructor's arguments=
=20
and _nothing else_. On the other hand, when I initialize an object with an=
=20
std::tuple object
X x1 =3D std::make_tuple(1, 2, 3);
X x2(std::make_tuple(1, 2, 3));
I definitely don't expect that items of the tuple will be interpreted as=20
arguments for the object's constructor. And I honestly don't understand why=
=20
braced-init-lists should behave differently.
Could you tell how the following string initialization is performed and how=
=20
it is supposed to be done?
std::pair<std::int8_t, std::int8_t> line_prefix(std::int8_t indent);
std::string gen_prefix_str(std::int8_t indent)
{
auto &&prefix =3D line_prefix(indent);
return { prefix.first, prefix.second };
}
=20
> Note that currently we are unable to
>> 1) copy-initialize a base class subobject, or a non-static data member i=
n=20
>> a mem-initializer-list, or an object created by a new-expression or by a=
=20
>> function-style type conversion,
>>
>
> Why would you *ever* want to copy-initialize any of those? Copy=20
> initialization is a functional subset of direct initialization. Anything=
=20
> you could do with copy initialization you can do with direct initializati=
on.
>
Good question. The short answer is: because I prefer to have=20
self-documenting code and good compile-time diagnostics.=20
Copy-initialization of an object tells to everyone that the initializer and=
=20
the object being initialized are value-related entities and implicit=20
conversion from the source value to the destination value is most likely=20
safe enough. When a copy-initialization causes a compilation error, a=20
similar well-formed direct-initialization may have either intended or=20
unintended behavior, so the code should be reviewed.
=20
> Oh, and one of the purposes of uniform initialization is so that you don'=
t=20
> have to know the difference between direct and copy initialization.
>
That's no so.
=20
> Granted, they reneged on that by making copy-list-initialization not use=
=20
> explicit constructors, but there's a point to that difference.
>
I don't see a point in that difference. We already have millions of classes=
=20
(BTW, some of them are part of the C+11 standard library) with non-explicit=
=20
constructors which have multiple parameters that are not aimed to=20
initialize items of a tuple-like object, so copy-list-initialization would=
=20
work when it is meaningless according to the original conception of=20
copy-initialization.
=20
> 3) move items of the initializer-list,
>>
>
> Of course not. Those items may be statically allocated.
>
That's not a convincing argument against movability. Moreover, both options=
=20
could coexist:
template <class... Items>
void f(braced_init_list<Items...> &&li); // 1
template <class... Items>
void f(braced_init_list<Items...> const &&li); // 2
void g()
{
f({1, 2}); // calls 1
f({1, 2}c); // calls 2
}
=20
> 4) handle items of unrelated types,
>>
> 5) forward initializer-lists.
>>
>
> ... What does that have to do with anything being discussed here?
>
The intention was to compare my list of desirable capabilities with those=
=20
we have now and those you are proposing here.
=20
> Alternative design might provide all these capabilities:
>>
>
>> std::string s =3D "text";
>> auto &&li =3D { 1, std::move(s), "string" };
>>
>
> What you want is something we already have. It's called a *tuple*.
>
And I already use it :-) However, tuple is not so convenient and powerful=
=20
as braced-initialized-list might be.
=20
> You can construct them from arbitrary arguments via make_tuple. If you=20
> want to forward things as a tuple, you use forward_as_tuple.
> =20
>
>> 2) the lifetime of the temporary object designated by expression { 1,=20
>> std::move(s), "string" } (call it braced-init-list object) is the same a=
s=20
>> the lifetime of the reference li (according to the usual rules for=20
>> reference-initialization).
>>
>
> Yeah, that doesn't work. If braced-init-list is an object, it's members *
> cannot* extend the lifetime of temporary parameters that are passed to=20
> the constructor of that object. The constructor's argument will bind to t=
he=20
> temporary *first*, and thus the lifetime will be the lifetime of the=20
> constructor argument, not the object itself. So that can't work.
>
Temporary objects created in a context of a braced-init-list may obey=20
special rules (so the second statement in the clause 3 would be satisfied).=
=20
I don't see problems here.
=20
> 3) Expressions 1, std::move(s) and "string" are used to initialize=20
>> references of types int &&, std::string && and const char (&)[7]=20
>> respectively. The reference of type int && is bound to a temporary objec=
t=20
>> whose lifetime is the same as the lifetime of the braced-init-list objec=
t.
>>
>> 5) Constructs
>>
>> Type x =3D y;
>> Type x{y};
>> new Type{y};
>> Type x{y};
>>
>> perform copy-initialization.
>>
>
> So basically, you're saying that list-initialization should have been=20
> defined in terms of copy initialization instead of direct initialization.=
=20
> That's *horrible*; why would we ever want that?
>
Currently for several contexts we don't have a syntax to express=20
copy-initialization semantics. {} seems to be convenient syntax.
=20
> The *entire point* of "uniform initialization" is that it is *uniformly*u=
sed to initialize=20
> *everything*.
>
Is this an end in itself? What is the point in similarity between code with=
=20
essentially different semantics? Maybe the goal is a code obfuscation? I=20
don't see any other explanation.
=20
> You cannot copy-initialize every object you would ever want to create.
>
Objects are created for concrete purposes. Copy-initialization may be=20
enough.
=20
> You're going to have to use direct initialization. So if you're going to=
=20
> create a uniform initialization syntax, in order for it to be used *
> everywhere*, it must use direct constructor initialization.
>
I can implement two versions of a generalized function: for=20
direct-initialization and for copy-initialization.
=20
#define FORWARD(x) static_cast<decltype(x)>(x)
// direct-initialization
template <class T, class... Params>
std::unique_ptr<T> make_unique(Params &&... params)
{
return explicit(::new T(FORWARD(params)...));
}
// copy-initialization
template <class T, class U>
std::unique_ptr<T> make_unique_value(U &¶m)
{
return explicit(::new T { FORWARD(param) } );
}
int main()
{
auto p1 =3D make_unique<std::vector<int>>({20});
// creates a container with 1 element initialized with value 20
auto p2 =3D make_unique<std::vector<int>>(20);
// creates a container with 20 value-initialized elements
auto p3 =3D make_unique_value<std::vector<int>>({20});
// creates a container with 1 element initialized with value 20
auto p4 =3D make_unique_value<std::vector<int>>(20);
// compile-time error
}
They provide full coverage of all possible variants of initialization. Try=
=20
to implement such generalized makers by means of your favourite "uniform=20
initialization".
--=20
------=_Part_11_32838542.1357139406815
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Wednesday, January 2, 2013 1:30:50 AM UTC+4, Nicol Bolas wrote:<blockquo=
te class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left:=
1px #ccc solid;padding-left: 1ex;">On Tuesday, January 1, 2013 8:55:34 AM =
UTC-8, Nikolay Ivchenkov wrote:<blockquote class=3D"gmail_quote" style=3D"m=
argin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex">On M=
onday, December 31, 2012 1:49:21 AM UTC+4, Nicol Bolas wrote:<blockquote cl=
ass=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #cc=
c solid;padding-left:1ex"><div title=3D"Introduction"><br><p>This idea was =
ultimately extended into what became known as uniform initialization:
one could initially any type via the use of a braced-init-list.=
Doing so provides a
number of advantages,</p></div></blockquote><div>Personally, I =
see only disadvantages. The initialization rules became too complex and har=
d to understand. In spite of that horrible complexity, we still don't have =
a lot of useful capabilities, that we might have if a more rational alterna=
tive design was accepted.<br></div></blockquote><div><br>But they're not co=
mplex; the rules are quite simple.</div></blockquote><div><br>IMO, they are=
neither simple nor intuitive, especially with regard to overload resolutio=
n.<br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;marg=
in-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><blockquote =
class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #=
ccc solid;padding-left:1ex"><div>I see your "problem" from the other side: =
why should I ever want to use<br><br><pre> std::vector<int> v1{20};=
<br><br>instead of<br><br> std::vector<int> v(20);<br><br>in order =
to get 20 value-initialized elements?<br></pre></div></blockquote><div><br>=
Because it always works the same way, regardless of whether 20 is a literal=
or `int()` (which causes the most vexing parse. Admittedly not useful, but=
I don't have to change my syntax just for that).<br></div></blockquote><di=
v><br>That's too weak argument, I can just replace int() with int{} or 0. N=
ote that when you want to pass a value-initialized temporary as a template =
argument, you can't use int() anyway, because it would be treated as a func=
tion type.<br><br>The downside of "almighty" initialization is weak compile=
-time checking, this is much more important factor for me:<br><br> &nb=
sp; int n =3D 20;<br> int *p =3D &n;<br> &=
nbsp; std::vector<int *> v{p};<br><br>Suppose that here I wante=
d to create *p value-initialized pointers, but I forgot to dereference p. T=
he mistake will not be diagnosed.<br><br></div><blockquote class=3D"gmail_q=
uote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pad=
ding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin=
-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>If we want to=
get 20 value-initialized elements, then<br><br><pre> std::vector<int&=
gt; v(20);<br><br></pre> does exactly what we want.<br></div></blockqu=
ote><div><br>That's not using uniform initialization syntax. The point of w=
hich is to <i>always</i> use {}; just read <a href=3D"http://isocpp.org/tou=
r" target=3D"_blank">Stroustrup's C++ tour on the website</a>, where he adv=
ocates <i>always</i> using {}.<br></div></blockquote><div><br>I don't see p=
oint there, his argumentation is neither convincing nor even plausible for =
me.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><blockquote c=
lass=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #c=
cc solid;padding-left:1ex"><div></div><blockquote class=3D"gmail_quote" sty=
le=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1e=
x"><div title=3D"Motivation and Scope"><p>Now, this may seem like a rather =
unimportant issue. After all, if I know that I have
to use constructor initialization with <span>vector<int><=
/span>, then I can simply do
that. But consider code that is generic on the <span>vector</sp=
an>'s type:</p><pre>template<typename T>
std::vector<T> MakeVector()
{
return std::vector<T>{20};
}</pre><p>By all rights, this code should always do the same thing: return =
a <span>vector</span>
containing 20 value-initialized elements.</p></div></blockquote=
><div>I would definitely prefer other behavior: it should _always_ create =
a single element initialized with value 20 (unfortunately, this is not so a=
ccording to the current rules).<br></div></blockquote><div><br>But if you w=
ant that behavior you can guarantee it by doing this:<br><br><div style=3D"=
background-color:rgb(250,250,250);border-color:rgb(187,187,187);border-styl=
e:solid;border-width:1px;word-wrap:break-word"><code><div><span style=3D"co=
lor:#008">return</span><span style=3D"color:#000"> std</span><span style=3D=
"color:#660">::</span><span style=3D"color:#000">vector</span><span style=
=3D"color:#660"><</span><span style=3D"color:#000">T</span><span style=
=3D"color:#660">>{{</span><span style=3D"color:#066">20</span><span styl=
e=3D"color:#660">}};</span><span style=3D"color:#000"><br></span></div></co=
de></div></div></blockquote><div><br>Actually, such "almighty" initializati=
on is unsafe again:<br><br> #include <iostream><br>=
#include <vector><br><br> int ma=
in()<br> {<br> =
for (auto &x : std::vector<int *>{{20}})<br> &nb=
sp; std::cout << x <<=
std::endl;<br> }<br><br>Here the container will have 20 =
value-initialized pointers, while I would prefer a compile-time error.<br>&=
nbsp;</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left=
: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>There's no way=
to do the opposite: guarantee that you're calling the constructor.<br></di=
v></blockquote><div><br>Well, something like this<br><br> =
explicit<T>(expr_list) // expression of type T<br><br>that would per=
form only direct-initialization exactly as in<br><br> T t=
(expr_list);<br><br>and (unlike to function-style type conversions) would b=
e unable to perform additional conversions that can be done via static_cast=
, reinterpret_cast and const_cast, could solve the problem.<br><br></div><b=
lockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;borde=
r-left: 1px #ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote=
" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-le=
ft:1ex"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8=
ex;border-left:1px #ccc solid;padding-left:1ex"><div title=3D"Motivation an=
d Scope"><p>This is of much greater concern when dealing with more intricat=
e templates. Consider
the following trivial template function:</p><pre>template<ty=
pename T>
T Process()
{
T t{};
//do stuff with t;
return T{t};
}</pre><p>This function creates a temporary, does some processing, and retu=
rns a copy of it.
This function requires that <span>T</span> be DefaultConstructi=
ble and
CopyConstructible, in addition to whatever <span>=93<span>do st=
uff with t</span>=94</span>
requires.</p></div></blockquote><div>This code can be rewritten=
as follows:<br> </div><div> template<typename T&=
gt;<br> T Process()<br> {<br> &nbs=
p; T t{};<br> &n=
bsp; // do stuff with t;<br>  =
; return t;<br> }<br></div></blockquote><div><br>Yes, but=
then it wouldn't be an example of the problem. It's an <i>example</i>, som=
ething that demonstrates the issue.<br></div></blockquote><div><br>There is=
an open core issue about this: http://www.open-std.org/jtc1/sc22/wg21/docs=
/cwg_active.html#1467<br>Probably, the rules will be changed according to t=
he suggestion published there.<br> </div><blockquote class=3D"gmail_qu=
ote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padd=
ing-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-=
left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><div title=3D"Design Overview"><p>The difference is =
that 13.3.1.7's list initialization overload resolution rules will
behave differently. list-braced-init-list initialization will w=
ork exactly as it does.
constr-braced-init-list will work opposite to the current way. =
That is, it will check
non-initializer_list constructors first, then go to the initial=
izer_list ones if no
matching constructors are found.</p></div></blockquote><div>Wha=
t is the point in calling a constructor with multiple parameters by use of =
a braced-init-list?<br></div></blockquote><div><br>This:<br><br><div style=
=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);border-=
style:solid;border-width:1px;word-wrap:break-word"><code><div><span style=
=3D"color:#000">std</span><span style=3D"color:#660">::</span><span style=
=3D"color:#008">string</span><span style=3D"color:#000"> </span><span style=
=3D"color:#606">GetLuaString</span><span style=3D"color:#660">()</span><spa=
n style=3D"color:#000"><br></span><span style=3D"color:#660">{</span><span =
style=3D"color:#000"><br> size_t len </span><span style=3D"color:#660=
">=3D</span><span style=3D"color:#000"> </span><span style=3D"color:#066">0=
</span><span style=3D"color:#660">;</span><span style=3D"color:#000"><br>&n=
bsp; </span><span style=3D"color:#008">const</span><span style=3D"color:#00=
0"> </span><span style=3D"color:#008">char</span><span style=3D"color:#000"=
> </span><span style=3D"color:#660">*</span><span style=3D"color:#000">str =
</span><span style=3D"color:#660">=3D</span><span style=3D"color:#000"> lua=
_tolstring</span><span style=3D"color:#660">(</span><span style=3D"color:#0=
00">L</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> =
</span><span style=3D"color:#660">-</span><span style=3D"color:#066">1</spa=
n><span style=3D"color:#660">,</span><span style=3D"color:#000"> </span><sp=
an style=3D"color:#660">&</span><span style=3D"color:#000">len</span><s=
pan style=3D"color:#660">);</span><span style=3D"color:#000"><br> </s=
pan><span style=3D"color:#660">{</span><span style=3D"color:#000">len</span=
><span style=3D"color:#660">,</span><span style=3D"color:#000"> str</span><=
span style=3D"color:#660">};</span><span style=3D"color:#000"> </span><span=
style=3D"color:#800">//No need to type std::string here.</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#660">}</span></div></code>=
</div><br>This is one of the nice things that uniform initialization gives =
is: it allows us to create things without pointlessly naming the type again=
..<br></div></blockquote><div><br>So, if we don't have a convenient syntax f=
or ()-style direct-initialization of returned objects, then instead of intr=
oducing such a useful thing into the language we need to invent a different=
kind initialization? Sorry, I don't see the point.<br><br>What is the conc=
eptual difference between copy-initialization and direct-initialization? Co=
py-initialization is used for relatively safe initialization of one entity =
by other entity with similar semantics and value. Direct-initialization is =
used in the rest of cases. When items of one tuple-like entity are copy-ini=
tialized by the respective items of another tuple-like entity, the sequence=
of such initializations can reasonably be treated as a copy-initialization=
:<br><br> std::vector<int> v =3D {1, 2, 3};<br><br>=
In C++03 brace-enclosed=20
initializer lists were used as tuple-like entities for initialization of=20
aggregates which can also be interpreted as tuple-like entities. In C++11 w=
e can implicitly (and suddenly) convert a tuple-like entity to an object wi=
th entirely different semantics.<br><br>()-style direct-initialization give=
s me ability to express the intention
that comma-separated items should be interpreted as constructor's=20
arguments and _nothing else_. On the other hand, when I initialize an objec=
t with an std::tuple object<br><br> X x1 =3D std::make_tu=
ple(1, 2, 3);<br> X x2(std::make_tuple(1, 2, 3));<br><br>=
I
definitely don't expect that items of the tuple will be interpreted as=20
arguments for the object's constructor. And I honestly don't understand why=
braced-init-lists should behave differently.<br><br>Could you tell how the=
following string initialization is performed and how it is supposed to be =
done?<br><br> std::pair<std::int8_t, std::int8_t> l=
ine_prefix(std::int8_t indent);<br><br> std::string gen_p=
refix_str(std::int8_t indent)<br> {<br> =
auto &&prefix =3D line_prefix(indent);<br>=
return { prefix.first, prefix.se=
cond };<br> }<br> </div><blockquote class=3D"gmail_q=
uote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pad=
ding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin=
-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div> Note th=
at currently we are unable to<br>1) copy-initialize a base class subobject,=
or a non-static data member in a mem-initializer-list, or an object create=
d by a new-expression or by a function-style type conversion,<br></div></bl=
ockquote><div><br>Why would you <i>ever</i> want to copy-initialize any of =
those? Copy initialization is a functional subset of direct initialization.=
Anything you could do with copy initialization you can do with direct init=
ialization.<br></div></blockquote><div><br>Good question. The short answer =
is: because I prefer to have self-documenting code and good compile-time di=
agnostics. Copy-initialization of an object tells to everyone that the init=
ializer and the object being initialized are value-related entities and imp=
licit conversion from the source value to the destination value is most lik=
ely safe enough. When a copy-initialization causes a compilation error, a s=
imilar well-formed direct-initialization may have either intended or uninte=
nded behavior, so the code should be reviewed.<br> </div><blockquote c=
lass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px=
#ccc solid;padding-left: 1ex;"><div>Oh, and one of the purposes of uniform=
initialization is so that you don't have to know the difference between di=
rect and copy initialization.</div></blockquote><div><br>That's no so.<br>&=
nbsp;</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left=
: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div> Granted, they=
reneged on that by making copy-list-initialization not use explicit constr=
uctors, but there's a point to that difference.<br></div></blockquote><div>=
<br>I don't see a point in that difference. We already have millions of cla=
sses (BTW, some of them are part of the C+11 standard library) with non-exp=
licit constructors which have multiple parameters that are not aimed to ini=
tialize items of a tuple-like object, so copy-list-initialization would wor=
k when it is meaningless according to the original conception of copy-initi=
alization.<br> </div><blockquote class=3D"gmail_quote" style=3D"margin=
: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><blo=
ckquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-le=
ft:1px #ccc solid;padding-left:1ex"><div>3) move items of the initializer-l=
ist,<br></div></blockquote><div><br>Of course not. Those items may be stati=
cally allocated.<br></div></blockquote><div><br>That's not a convincing arg=
ument against movability. Moreover, both options could coexist:<br><br>&nbs=
p; template <class... Items><br> &=
nbsp; void f(braced_init_list<Items...> &&li); //=
1<br> template <class... Items><br> &nb=
sp; void f(braced_init_list<Items...> const &=
amp;&li); // 2<br><br> void g()<br> =
{<br> f({1, 2}); // calls 1<br>&=
nbsp; f({1, 2}c); // calls 2<br> &=
nbsp; }<br> </div><blockquote class=3D"gmail_quote" style=3D"mar=
gin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><=
blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border=
-left:1px #ccc solid;padding-left:1ex"><div>4) handle items of unrelated ty=
pes,</div></blockquote><blockquote class=3D"gmail_quote" style=3D"margin:0;=
margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>5) forw=
ard initializer-lists.<br></div></blockquote><div><br>... What does that ha=
ve to do with anything being discussed here?<br></div></blockquote><div><br=
>The intention was to compare my list of desirable capabilities with those =
we have now and those you are proposing here.<br> </div><blockquote cl=
ass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px =
#ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"m=
argin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div=
>Alternative design might provide all these capabilities:<br></div></blockq=
uote><div></div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-=
left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div><br> &nbs=
p; std::string s =3D "text";<br> auto &&li =
=3D { 1, std::move(s), "string" };<br></div></blockquote><div><br>What you =
want is something we already have. It's called a <i>tuple</i>.</div></block=
quote><div><br>And I already use it :-) However, tuple is not so convenient=
and powerful as braced-initialized-list might be.<br> </div><blockquo=
te class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left:=
1px #ccc solid;padding-left: 1ex;"><div> You can construct them from arbit=
rary arguments via make_tuple. If you want to forward things as a tuple, yo=
u use forward_as_tuple.<br> </div><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1=
ex"><div>2) the lifetime of the temporary object designated by expression {=
1, std::move(s), "string" } (call it braced-init-list object) is the same =
as the lifetime of the reference li (according to the usual rules for refer=
ence-initialization).<br></div></blockquote><div><br>Yeah, that doesn't wor=
k. If braced-init-list is an object, it's members <i>cannot</i> extend the =
lifetime of temporary parameters that are passed to the constructor of that=
object. The constructor's argument will bind to the temporary <i>first</i>=
, and thus the lifetime will be the lifetime of the constructor argument, n=
ot the object itself. So that can't work.<br></div></blockquote><div><br>Te=
mporary objects created in a context of a braced-init-list may obey special=
rules (so the second statement in the clause 3 would be satisfied). I don'=
t see problems here.<br> </div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex=
;border-left:1px #ccc solid;padding-left:1ex"><div>3) Expressions 1, std::m=
ove(s) and "string" are used to initialize references of types int &&am=
p;, std::string && and const char (&)[7] respectively. The refe=
rence of type int && is bound to a temporary object whose lifetime =
is the same as the lifetime of the braced-init-list object.<br><br>5) Const=
ructs<br><br> Type x =3D y;<br> Type x{=
y};<br> new Type{y};<br> Type x{y};<br>=
<br>perform copy-initialization.<br></div></blockquote><div><br>So basicall=
y, you're saying that list-initialization should have been defined in terms=
of copy initialization instead of direct initialization. That's <i>horribl=
e</i>; why would we ever want that?</div></blockquote><div><br>Currently fo=
r several contexts we don't have a syntax to express copy-initialization se=
mantics. {} seems to be convenient syntax.<br> </div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><div>The <i>entire point</i> of "uniform initia=
lization" is that it is <i>uniformly</i> used to initialize <i>everything</=
i>.</div></blockquote><div><br>Is this an end in itself? What is the point =
in similarity between code with essentially different semantics? Maybe the =
goal is a code obfuscation? I don't see any other explanation.<br> </d=
iv><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;"><div> You cannot copy-initi=
alize every object you would ever want to create.</div></blockquote><div><b=
r>Objects are created for concrete purposes. Copy-initialization may be eno=
ugh.<br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;ma=
rgin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div> You'=
re going to have to use direct initialization. So if you're going to create=
a uniform initialization syntax, in order for it to be used <i>everywhere<=
/i>, it must use direct constructor initialization.<br></div></blockquote><=
div><br>I can implement two versions of a generalized function: for direct-=
initialization and for copy-initialization.<br> <br> =
#define FORWARD(x) static_cast<decltype(x)>(x)<br><br> &n=
bsp; // direct-initialization<br> template <class T, c=
lass... Params><br> std::uniqu=
e_ptr<T> make_unique(Params &&... params)<br> &nbs=
p; {<br> return explicit(::new T(=
FORWARD(params)...));<br> }<br><br> // =
copy-initialization<br> template <class T, class U>=
<br> std::unique_ptr<T> mak=
e_unique_value(U &&param)<br> {<br> &n=
bsp; return explicit(::new T { FORWARD(param) } );<=
br> }<br><br> int main()<br>  =
; {<br> auto p1 =3D make_un=
ique<std::vector<int>>({20});<br> =
// creates a container with 1 element initialized with value 2=
0<br><br> auto p2 =3D make_unique=
<std::vector<int>>(20);<br> =
// creates a container with 20 value-initialized elements<br><br>&nb=
sp; auto p3 =3D make_unique_value<st=
d::vector<int>>({20});<br> &nbs=
p; // creates a container with 1 element initialized with value 20<br><br>&=
nbsp; auto p4 =3D make_unique_value<=
std::vector<int>>(20);<br> &nbs=
p; // compile-time error<br> }<br><br>They provide full c=
overage of all possible variants of initialization. Try to implement such g=
eneralized makers by means of your favourite "uniform initialization".<br><=
/div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_11_32838542.1357139406815--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Wed, 2 Jan 2013 07:46:16 -0800 (PST)
Raw View
------=_Part_188_17566676.1357141576093
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Wednesday, January 2, 2013 1:30:50 AM UTC+4, Nicol Bolas wrote:
>
> On Tuesday, January 1, 2013 8:55:34 AM UTC-8, Nikolay Ivchenkov wrote:
>>
>> On Monday, December 31, 2012 1:49:21 AM UTC+4, Nicol Bolas wrote:
>>>
>>>
>>> Personally, I see only disadvantages. The initialization rules became=
=20
>> too complex and hard to understand. In spite of that horrible complexity=
,=20
>> we still don't have a lot of useful capabilities, that we might have if =
a=20
>> more rational alternative design was accepted.
>>
>
> But they're not complex; the rules are quite simple.
>
IMO, they are neither simple nor intuitive, especially with regard to=20
overload resolution.
=20
> I see your "problem" from the other side: why should I ever want to use
>>
>> std::vector<int> v1{20};
>>
>> instead of
>>
>> std::vector<int> v(20);
>>
>> in order to get 20 value-initialized elements?
>>
>>
> Because it always works the same way, regardless of whether 20 is a=20
> literal or `int()` (which causes the most vexing parse. Admittedly not=20
> useful, but I don't have to change my syntax just for that).
>
That's too weak argument, I can just replace int() with int{} or 0. Note=20
that when you want to pass a value-initialized temporary as a template=20
argument, you can't use int() anyway, because it would be treated as a=20
function type.
The downside of "almighty" initialization is weak compile-time checking,=20
this is much more important factor for me:
int n =3D 20;
int *p =3D &n;
std::vector<int *> v{p};
Suppose that here I wanted to create *p value-initialized pointers, but I=
=20
forgot to dereference p. The mistake will not be diagnosed.
The point of which is to *always* use {}; just read Stroustrup's C++ tour=
=20
> on the website <http://isocpp.org/tour>, where he advocates *always*using=
{}.
>
I don't see point there, his argumentation is neither convincing nor even=
=20
plausible for me.
template<typename T>
>>> std::vector<T> MakeVector()
>>> {
>>> return std::vector<T>{20};
>>> }
>>>
>>> By all rights, this code should always do the same thing: return a=20
>>> vector containing 20 value-initialized elements.
>>>
>> I would definitely prefer other behavior: it should _always_ create a=20
>> single element initialized with value 20 (unfortunately, this is not so=
=20
>> according to the current rules).
>>
>
> But if you want that behavior you can guarantee it by doing this:
>
> return std::vector<T>{{20}};
>
Actually, such "almighty" initialization is unsafe again:
#include <iostream>
#include <vector>
int main()
{
for (auto &x : std::vector<int *>{{20}})
std::cout << x << std::endl;
}
Here the container will have 20 value-initialized pointers, while I would=
=20
prefer a compile-time error.
=20
> There's no way to do the opposite: guarantee that you're calling the=20
> constructor.
>
Well, something like this
explicit<T>(expr_list) // expression of type T
that would perform only direct-initialization exactly as in
T t(expr_list);
and (unlike to function-style type conversions) would be unable to perform=
=20
additional conversions that can be done via static_cast, reinterpret_cast=
=20
and const_cast, could solve the problem.
This is of much greater concern when dealing with more intricate templates.=
=20
>>> Consider the following trivial template function:
>>>
>>> template<typename T>
>>> T Process()
>>> {
>>> T t{};
>>> //do stuff with t;
>>> return T{t};
>>> }
>>>
>>> This function creates a temporary, does some processing, and returns a=
=20
>>> copy of it. This function requires that T be DefaultConstructible and=
=20
>>> CopyConstructible, in addition to whatever =93do stuff with t=94 requir=
es.
>>>
>> There is an open core issue about this:=20
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1467
Probably, the rules will be changed according to the suggestion published=
=20
there.
=20
> What is the point in calling a constructor with multiple parameters by us=
e=20
>> of a braced-init-list?
>>
>
> This:
>
> std::string GetLuaString()
> {
> size_t len =3D 0;
> const char *str =3D lua_tolstring(L, -1, &len);
> {len, str}; //No need to type std::string here.
> }
>
> This is one of the nice things that uniform initialization gives is: it=
=20
> allows us to create things without pointlessly naming the type again.
>
So, if we don't have a convenient syntax for ()-style direct-initialization=
=20
of returned objects, then instead of introducing such a useful thing into=
=20
the language we need to invent a different kind initialization? Sorry, I=20
don't see the point.
What is the conceptual difference between copy-initialization and=20
direct-initialization? Copy-initialization is used for relatively safe=20
initialization of one entity by other entity with similar semantics and=20
value. Direct-initialization is used in the rest of cases. When items of=20
one tuple-like entity are copy-initialized by the respective items of=20
another tuple-like entity, the sequence of such initializations can=20
reasonably be treated as a copy-initialization:
std::vector<int> v =3D {1, 2, 3};
In C++03 brace-enclosed initializer lists were used as tuple-like entities=
=20
for initialization of aggregates which can also be interpreted as=20
tuple-like entities. In C++11 we can implicitly (and suddenly) convert a=20
tuple-like entity to an object with entirely different semantics.
()-style direct-initialization gives me ability to express the intention=20
that comma-separated items should be interpreted as constructor's arguments=
=20
and _nothing else_. On the other hand, when I initialize an object with an=
=20
std::tuple object
X x1 =3D std::make_tuple(1, 2, 3);
X x2(std::make_tuple(1, 2, 3));
I definitely don't expect that items of the tuple will be interpreted as=20
arguments for the object's constructor. And I honestly don't understand why=
=20
braced-init-lists should behave differently.
Could you tell how the following string initialization is performed and how=
=20
it is supposed to be done?
std::pair<std::int8_t, std::int8_t> line_prefix(std::int8_t indent);
std::string gen_prefix_str(std::int8_t indent)
{
auto &&prefix =3D line_prefix(indent);
return { prefix.first, prefix.second };
}
=20
> Note that currently we are unable to
>> 1) copy-initialize a base class subobject, or a non-static data member i=
n=20
>> a mem-initializer-list, or an object created by a new-expression or by a=
=20
>> function-style type conversion,
>>
>
> Why would you *ever* want to copy-initialize any of those? Copy=20
> initialization is a functional subset of direct initialization. Anything=
=20
> you could do with copy initialization you can do with direct initializati=
on.
>
Good question. The short answer is: because I prefer to have=20
self-documenting code and good compile-time diagnostics.=20
Copy-initialization of an object tells to everyone that the initializer and=
=20
the object being initialized are value-related entities and implicit=20
conversion from the source value to the destination value is most likely=20
safe enough. When a copy-initialization causes a compilation error, a=20
similar well-formed direct-initialization may have either intended or=20
unintended behavior, so the code should be reviewed.
=20
> Oh, and one of the purposes of uniform initialization is so that you don'=
t=20
> have to know the difference between direct and copy initialization.
>
That's no so.
=20
> Granted, they reneged on that by making copy-list-initialization not use=
=20
> explicit constructors, but there's a point to that difference.
>
I don't see a point in that difference. We already have millions of classes=
=20
(BTW, some of them are part of the C+11 standard library) with non-explicit=
=20
constructors which have multiple parameters that are not aimed to=20
initialize items of a tuple-like object, so copy-list-initialization would=
=20
work when it is meaningless according to the original conception of=20
copy-initialization.
=20
> 3) move items of the initializer-list,
>>
>
> Of course not. Those items may be statically allocated.
>
That's not a convincing argument against movability. Moreover, both options=
=20
could coexist:
template <class... Items>
void f(braced_init_list<Items...> &&li); // 1
template <class... Items>
void f(braced_init_list<Items...> const &&li); // 2
void g()
{
f({1, 2}); // calls 1
f({1, 2}c); // calls 2
}
=20
> 4) handle items of unrelated types,
>>
> 5) forward initializer-lists.
>>
>
> ... What does that have to do with anything being discussed here?
>
The intention was to compare my list of desirable capabilities with those=
=20
we have now and those you are proposing here.
=20
> What you want is something we already have. It's called a *tuple*.
>
And I already use it :-) However, tuple is not so convenient and powerful=
=20
as braced-initialized-list might be.
=20
> 2) the lifetime of the temporary object designated by expression { 1,=20
>> std::move(s), "string" } (call it braced-init-list object) is the same a=
s=20
>> the lifetime of the reference li (according to the usual rules for=20
>> reference-initialization).
>>
>
> Yeah, that doesn't work. If braced-init-list is an object, it's members *
> cannot* extend the lifetime of temporary parameters that are passed to=20
> the constructor of that object. The constructor's argument will bind to t=
he=20
> temporary *first*, and thus the lifetime will be the lifetime of the=20
> constructor argument, not the object itself. So that can't work.
>
Temporary objects created in a context of a braced-init-list may obey=20
special rules (so the second statement in the clause 3 would be satisfied).=
=20
I don't see problems here.
3) Expressions 1, std::move(s) and "string" are used to initialize=20
>> references of types int &&, std::string && and const char (&)[7]=20
>> respectively. The reference of type int && is bound to a temporary objec=
t=20
>> whose lifetime is the same as the lifetime of the braced-init-list objec=
t.
>>
>> 5) Constructs
>>
>> Type x =3D y;
>> Type x{y};
>> new Type{y};
>> Type x{y};
>>
>> perform copy-initialization.
>>
>
> So basically, you're saying that list-initialization should have been=20
> defined in terms of copy initialization instead of direct initialization.=
=20
> That's *horrible*; why would we ever want that?
>
Currently for several contexts we don't have a syntax to express=20
copy-initialization semantics. {} seems to be convenient syntax.
=20
> The *entire point* of "uniform initialization" is that it is *uniformly*u=
sed to initialize=20
> *everything*.
>
Is this an end in itself? What is the point in similarity between code with=
=20
essentially different semantics? Maybe the goal is a code obfuscation? I=20
don't see any other explanation.
=20
> You cannot copy-initialize every object you would ever want to create.=20
> You're going to have to use direct initialization. So if you're going to=
=20
> create a uniform initialization syntax, in order for it to be used *
> everywhere*, it must use direct constructor initialization.
>
I can implement two versions of a generalized function: for=20
direct-initialization and for copy-initialization.
#define FORWARD(x) static_cast<decltype(x)>(x)
template <class T, class... Params>
std::unique_ptr<T> make_unique(Params &&... params)
{
return explicit(::new T(FORWARD(params)...));
}
template <class T, class U>
std::unique_ptr<T> make_unique_value(U &¶m)
{
return explicit(::new T{FORWARD(param)});
}
int main()
{
auto p1 =3D make_unique<std::vector<int>>({20});
// creates a container with 1 element initialized with value 20
auto p2 =3D make_unique<std::vector<int>>(20);
// creates a container with 20 value-initialized elements
auto p3 =3D make_unique_value<std::vector<int>>({20});
// creates a container with 1 element initialized with value 20
auto p4 =3D make_unique_value<std::vector<int>>(20);
// compile-time error
}
=20
They provide full coverage of all possible variants of initialization. Try=
=20
to implement such generalized makers by means of {}-like "uniform=20
initialization".
--=20
------=_Part_188_17566676.1357141576093
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
<div class=3D"GLTURNLH5">On Wednesday, January 2, 2013 1:30:50 AM UTC+4, Ni=
col Bolas wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-=
left:0.8ex;border-left:1px #ccc solid;padding-left:1ex">On Tuesday, January=
1, 2013 8:55:34 AM UTC-8, Nikolay Ivchenkov wrote:<blockquote class=3D"gma=
il_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;pa=
dding-left:1ex">On Monday, December 31, 2012 1:49:21 AM UTC+4, Nicol Bolas =
wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex=
;border-left:1px #ccc solid;padding-left:1ex"><div title=3D"Introduction"><=
br></div></blockquote><div>Personally,
I see only disadvantages. The initialization rules became too complex=20
and hard to understand. In spite of that horrible complexity, we still=20
don't have a lot of useful capabilities, that we might have if a more=20
rational alternative design was accepted.<br></div></blockquote><div><br>Bu=
t they're not complex; the rules are quite simple.</div></blockquote></div>=
<div><br>IMO, they are neither simple nor intuitive, especially with regard=
to overload resolution.<br> </div><div class=3D"GLTURNLH5"><blockquot=
e class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px=
#ccc solid;padding-left:1ex"><blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>=
I see your "problem" from the other side: why should I ever want to use<br>=
<br><pre> std::vector<int> v1{20};<br><br>instead of<br><br> std:=
:vector<int> v(20);<br><br>in order to get 20 value-initialized eleme=
nts?<br></pre></div></blockquote><div><br>Because
it always works the same way, regardless of whether 20 is a literal or=20
`int()` (which causes the most vexing parse. Admittedly not useful, but I
don't have to change my syntax just for that).<br></div></blockquote></div=
><div><br>That's
too weak argument, I can just replace int() with int{} or 0. Note that=20
when you want to pass a value-initialized temporary as a template=20
argument, you can't use int() anyway, because it would be treated as a=20
function type.<br><br>The downside of "almighty" initialization is weak com=
pile-time checking, this is much more important factor for me:<br><br> =
; int n =3D 20;<br> int *p =3D &n;<br>&nb=
sp; std::vector<int *> v{p};<br><br>Suppose
that here I wanted to create *p value-initialized pointers, but I=20
forgot to dereference p. The mistake will not be diagnosed.<br><br></div><d=
iv class=3D"GLTURNLH5"><blockquote class=3D"gmail_quote" style=3D"margin:0;=
margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>The poi=
nt of which is to <i>always</i> use {}; just read <a href=3D"http://isocpp.=
org/tour" target=3D"_blank">Stroustrup's C++ tour on the website</a>, where=
he advocates <i>always</i> using {}.<br></div></blockquote></div><div><br>=
I don't see point there, his argumentation is neither convincing nor even p=
lausible for me.<br><br></div><div class=3D"GLTURNLH5"><blockquote class=3D=
"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc soli=
d;padding-left:1ex"><blockquote class=3D"gmail_quote" style=3D"margin:0;mar=
gin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc=
solid;padding-left:1ex"><div title=3D"Motivation and Scope"><pre>template&=
lt;typename T>
std::vector<T> MakeVector()
{
return std::vector<T>{20};
}</pre><p>By all rights, this code should always do the same thing: return =
a <span>vector</span>
containing 20 value-initialized elements.</p></div></blockquote=
><div>I
would definitely prefer other behavior: it should _always_ create a=20
single element initialized with value 20 (unfortunately, this is not so=20
according to the current rules).<br></div></blockquote><div><br>But if you =
want that behavior you can guarantee it by doing this:<br><br><div style=3D=
"background-color:rgb(250,250,250);border-color:rgb(187,187,187);border-sty=
le:solid;border-width:1px;word-wrap:break-word"><code><div><span style=3D"c=
olor:#008">return</span><span style=3D"color:#000"> std</span><span style=
=3D"color:#660">::</span><span style=3D"color:#000">vector</span><span styl=
e=3D"color:#660"><</span><span style=3D"color:#000">T</span><span style=
=3D"color:#660">>{{</span><span style=3D"color:#066">20</span><span styl=
e=3D"color:#660">}};</span><span style=3D"color:#000"><br></span></div></co=
de></div></div></blockquote></div><div><br>Actually, such "almighty" initia=
lization is unsafe again:<br><br> #include <iostream&g=
t;<br> #include <vector><br><br> =
int main()<br> {<br> &=
nbsp; for (auto &x : std::vector<int *>{{20}})<br> &nb=
sp; std::cout << x &l=
t;< std::endl;<br> }<br><br>Here the container will ha=
ve 20 value-initialized pointers, while I would prefer a compile-time error=
..<br> </div><div class=3D"GLTURNLH5"><blockquote class=3D"gmail_quote"=
style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-lef=
t:1ex"><div>There's no way to do the opposite: guarantee that you're callin=
g the constructor.<br></div></blockquote></div><div><br>Well, something lik=
e this<br><br> explicit<T>(expr_list) // expression=
of type T<br><br>that would perform only direct-initialization exactly as =
in<br><br> T t(expr_list);<br><br>and
(unlike to function-style type conversions) would be unable to perform=20
additional conversions that can be done via static_cast,=20
reinterpret_cast and const_cast, could solve the problem.<br><br></div><div=
class=3D"GLTURNLH5"><blockquote class=3D"gmail_quote" style=3D"margin:0;ma=
rgin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote cl=
ass=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #cc=
c solid;padding-left:1ex"><blockquote class=3D"gmail_quote" style=3D"margin=
:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div titl=
e=3D"Motivation and Scope"><p>This is of much greater concern when dealing =
with more intricate templates. Consider
the following trivial template function:</p><pre>template<ty=
pename T>
T Process()
{
T t{};
//do stuff with t;
return T{t};
}</pre><p>This function creates a temporary, does some processing, and retu=
rns a copy of it.
This function requires that <span>T</span> be DefaultConstructi=
ble and
CopyConstructible, in addition to whatever <span>=93<span>do st=
uff with t</span>=94</span>
requires.<br></p></div></blockquote></blockquote></blockquote><=
/div><div>There is an open core issue about this: <a href=3D"http://www.ope=
n-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1467" target=3D"_blank">http:=
//www.open-std.org/jtc1/<wbr>sc22/wg21/docs/cwg_active.<wbr>html#1467</a><b=
r>Probably, the rules will be changed according to the suggestion published=
there.<br> </div><div class=3D"GLTURNLH5"><blockquote class=3D"gmail_=
quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;paddi=
ng-left:1ex"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-lef=
t:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>What is the point=
in calling a constructor with multiple parameters by use of a braced-init-=
list?<br></div></blockquote><div><br>This:<br><br><div style=3D"background-=
color:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;bor=
der-width:1px;word-wrap:break-word"><code><div><span style=3D"color:#000">s=
td</span><span style=3D"color:#660">::</span><span style=3D"color:#008">str=
ing</span><span style=3D"color:#000"> </span><span style=3D"color:#606">Get=
LuaString</span><span style=3D"color:#660">()</span><span style=3D"color:#0=
00"><br></span><span style=3D"color:#660">{</span><span style=3D"color:#000=
"><br> size_t len </span><span style=3D"color:#660">=3D</span><span s=
tyle=3D"color:#000"> </span><span style=3D"color:#066">0</span><span style=
=3D"color:#660">;</span><span style=3D"color:#000"><br> </span><span =
style=3D"color:#008">const</span><span style=3D"color:#000"> </span><span s=
tyle=3D"color:#008">char</span><span style=3D"color:#000"> </span><span sty=
le=3D"color:#660">*</span><span style=3D"color:#000">str </span><span style=
=3D"color:#660">=3D</span><span style=3D"color:#000"> lua_tolstring</span><=
span style=3D"color:#660">(</span><span style=3D"color:#000">L</span><span =
style=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=
=3D"color:#660">-</span><span style=3D"color:#066">1</span><span style=3D"c=
olor:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color:=
#660">&</span><span style=3D"color:#000">len</span><span style=3D"color=
:#660">);</span><span style=3D"color:#000"><br> </span><span style=3D=
"color:#660">{</span><span style=3D"color:#000">len</span><span style=3D"co=
lor:#660">,</span><span style=3D"color:#000"> str</span><span style=3D"colo=
r:#660">};</span><span style=3D"color:#000"> </span><span style=3D"color:#8=
00">//No need to type std::string here.</span><span style=3D"color:#000"><b=
r></span><span style=3D"color:#660">}</span></div></code></div><br>This
is one of the nice things that uniform initialization gives is: it=20
allows us to create things without pointlessly naming the type again.<br></=
div></blockquote></div><div><br>So,
if we don't have a convenient syntax for ()-style direct-initialization
of returned objects, then instead of introducing such a useful thing=20
into the language we need to invent a different kind initialization?=20
Sorry, I don't see the point.<br><br>What is the conceptual difference=20
between copy-initialization and direct-initialization?=20
Copy-initialization is used for relatively safe initialization of one=20
entity by other entity with similar semantics and value.=20
Direct-initialization is used in the rest of cases. When items of one=20
tuple-like entity are copy-initialized by the respective items of=20
another tuple-like entity, the sequence of such initializations can=20
reasonably be treated as a copy-initialization:<div class=3D"GLTURNLH5"><br=
> std::vector<int> v =3D {1, 2, 3};<br><br></div>In
C++03 brace-enclosed=20
initializer lists were used as tuple-like entities for initialization of
=20
aggregates which can also be interpreted as tuple-like entities. In=20
C++11 we can implicitly (and suddenly) convert a tuple-like entity to an
object with entirely different semantics.<br><br>()-style direct-initializ=
ation gives me ability to express the intention
that comma-separated items should be interpreted as constructor's=20
arguments and _nothing else_. On the other hand, when I initialize an objec=
t with an std::tuple object<br><br> X x1 =3D std::make_tu=
ple(1, 2, 3);<br> X x2(std::make_tuple(1, 2, 3));<br><br>=
I
definitely don't expect that items of the tuple will be interpreted as=20
arguments for the object's constructor. And I honestly don't understand why=
braced-init-lists should behave differently.<br><br>Could you tell how the=
following string initialization is performed and how it is supposed to be =
done?<br><br> std::pair<std::int8_t, std::int8_t> l=
ine_prefix(std::int8_t indent);<br><br> std::string gen_p=
refix_str(std::int8_t indent)<br> {<br> =
auto &&prefix =3D line_prefix(indent);<br>=
return { prefix.first, prefix.se=
cond };<br> }<br> </div><div class=3D"GLTURNLH5"><bl=
ockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-l=
eft:1px #ccc solid;padding-left:1ex"><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex=
"><div> Note that currently we are unable to<br>1)
copy-initialize a base class subobject, or a non-static data member in a
mem-initializer-list, or an object created by a new-expression or by a=20
function-style type conversion,<br></div></blockquote><div><br>Why would yo=
u <i>ever</i>
want to copy-initialize any of those? Copy initialization is a=20
functional subset of direct initialization. Anything you could do with=20
copy initialization you can do with direct initialization.<br></div></block=
quote></div><div><br>Good
question. The short answer is: because I prefer to have=20
self-documenting code and good compile-time diagnostics.=20
Copy-initialization of an object tells to everyone that the initializer=20
and the object being initialized are value-related entities and implicit
conversion from the source value to the destination value is most=20
likely safe enough. When a copy-initialization causes a compilation=20
error, a similar well-formed direct-initialization may have either=20
intended or unintended behavior, so the code should be reviewed.<br> <=
/div><div class=3D"GLTURNLH5"><blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>=
Oh,
and one of the purposes of uniform initialization is so that you don't=20
have to know the difference between direct and copy initialization.</div></=
blockquote></div><div><br>That's no so.<br> </div><div class=3D"GLTURN=
LH5"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;=
border-left:1px #ccc solid;padding-left:1ex"><div>
Granted, they reneged on that by making copy-list-initialization not=20
use explicit constructors, but there's a point to that difference.<br></div=
></blockquote></div><div><br>I
don't see a point in that difference. We already have millions of=20
classes (BTW, some of them are part of the C+11 standard library) with=20
non-explicit constructors which have multiple parameters that are not=20
aimed to initialize items of a tuple-like object, so=20
copy-list-initialization would work when it is meaningless according to=20
the original conception of copy-initialization.<br> </div><div class=
=3D"GLTURNLH5"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-l=
eft:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class=3D=
"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc soli=
d;padding-left:1ex"><div>3) move items of the initializer-list,<br></div></=
blockquote><div><br>Of course not. Those items may be statically allocated.=
<br></div></blockquote></div><div><br>That's not a convincing argument agai=
nst movability. Moreover, both options could coexist:<br><br> &n=
bsp; template <class... Items><br>  =
; void f(braced_init_list<Items...> &&li); // 1<br>&nbs=
p; template <class... Items><br> &=
nbsp; void f(braced_init_list<Items...> const &&l=
i); // 2<br><br> void g()<br> {<br>&nbs=
p; f({1, 2}); // calls 1<br>  =
; f({1, 2}c); // calls 2<br>  =
; }<br> </div><div class=3D"GLTURNLH5"><blockquote class=3D"gmail_quot=
e" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-l=
eft:1ex"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.=
8ex;border-left:1px #ccc solid;padding-left:1ex"><div>4) handle items of un=
related types,</div></blockquote><blockquote class=3D"gmail_quote" style=3D=
"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><d=
iv>5) forward initializer-lists.<br></div></blockquote><div><br>... What do=
es that have to do with anything being discussed here?<br></div></blockquot=
e></div><div><br>The intention was to compare my list of desirable capabili=
ties with those we have now and those you are proposing here.<br> </di=
v><div class=3D"GLTURNLH5"><blockquote class=3D"gmail_quote" style=3D"margi=
n:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>Wha=
t you want is something we already have. It's called a <i>tuple</i>.</div><=
/blockquote></div><div><br>And I already use it :-) However, tuple is not s=
o convenient and powerful as braced-initialized-list might be.<br> </d=
iv><div class=3D"GLTURNLH5"><blockquote class=3D"gmail_quote" style=3D"marg=
in:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div></=
div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;b=
order-left:1px #ccc solid;padding-left:1ex"><div>2)
the lifetime of the temporary object designated by expression { 1,=20
std::move(s), "string" } (call it braced-init-list object) is the same=20
as the lifetime of the reference li (according to the usual rules for=20
reference-initialization).<br></div></blockquote><div><br>Yeah, that doesn'=
t work. If braced-init-list is an object, it's members <i>cannot</i>
extend the lifetime of temporary parameters that are passed to the=20
constructor of that object. The constructor's argument will bind to the=20
temporary <i>first</i>, and thus the lifetime will be the lifetime of the c=
onstructor argument, not the object itself. So that can't work.<br></div></=
blockquote></div><div class=3D"GLTURNLH5"><br>Temporary
objects created in a context of a braced-init-list may obey special=20
rules (so the second statement in the clause 3 would be satisfied). I=20
don't see problems here.<br><br><blockquote class=3D"gmail_quote" style=3D"=
margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;=
"><div></div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-lef=
t:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>3)
Expressions 1, std::move(s) and "string" are used to initialize=20
references of types int &&, std::string && and const=20
char (&)[7] respectively. The reference of type int && is=20
bound to a temporary object whose lifetime is the same as the lifetime=20
of the braced-init-list object.<br><br>5) Constructs<br><br> &nb=
sp; Type x =3D y;<br> Type x{y};<br> ne=
w Type{y};<br> Type x{y};<br><br>perform copy-initializat=
ion.<br></div></blockquote><div><br>So
basically, you're saying that list-initialization should have been=20
defined in terms of copy initialization instead of direct=20
initialization. That's <i>horrible</i>; why would we ever want that?<br></d=
iv></blockquote><div><br>Currently for several contexts we don't have a syn=
tax to express copy-initialization semantics. {} seems to be convenient syn=
tax.<br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;ma=
rgin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>The <=
i>entire point</i> of "uniform initialization" is that it is <i>uniformly</=
i> used to initialize <i>everything</i>.</div></blockquote><div><br>Is this=
an end in itself? What is the point in similarity between code with essent=
ially different semantics? Maybe the goal is a code obfuscation? I don't se=
e any other explanation.<br> </div><blockquote class=3D"gmail_quote" s=
tyle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-le=
ft: 1ex;"><div>
You cannot copy-initialize every object you would ever want to create.=20
You're going to have to use direct initialization. So if you're going to
create a uniform initialization syntax, in order for it to be used <i>ever=
ywhere</i>, it must use direct constructor initialization.<br></div></block=
quote><div><br>I can implement two versions of a generalized function: for =
direct-initialization and for copy-initialization.<br><br>  =
; #define FORWARD(x) static_cast<decltype(x)>(x)<br><br> &=
nbsp; template <class T, class... Params><br> =
std::unique_ptr<T> make_unique(Params &&..=
.. params)<br> {<br> &n=
bsp; return explicit(::new T(FORWARD(params)...));<br> }<=
br><br> template <class T, class U><br> =
std::unique_ptr<T> make_unique_value(U=
&&param)<br> {<br> =
return explicit(::new T{FORWARD(param)});<br>  =
; }<br><br> int main()<br> {<br> &=
nbsp; auto p1 =3D make_unique<std::vector&=
lt;int>>({20});<br> // crea=
tes a container with 1 element initialized with value 20<br><br>  =
; auto p2 =3D make_unique<std::vector<i=
nt>>(20);<br> // creates a =
container with 20 value-initialized elements<br><br>  =
; auto p3 =3D make_unique_value<std::vector<int>=
>({20});<br> // creates a cont=
ainer with 1 element initialized with value 20<br><br> &nb=
sp; auto p4 =3D make_unique_value<std::vector<int&g=
t;>(20);<br> // compile-time e=
rror<br> }<br> <br>They provide full coverage of all=
possible variants of initialization. Try to implement such generalized mak=
ers by means of {}-like "uniform initialization".<br></div></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_188_17566676.1357141576093--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Wed, 2 Jan 2013 07:53:08 -0800 (PST)
Raw View
------=_Part_5_31873030.1357141988797
Content-Type: text/plain; charset=ISO-8859-1
[Reposting truncated part of the message]
#define FORWARD(x) static_cast<decltype(x)>(x)
template <class T, class... Params>
std::unique_ptr<T> make_unique(Params &&... params)
{
return explicit(::new T(FORWARD(params)...));
}
template <class T, class U>
std::unique_ptr<T> make_unique_value(U &¶m)
{
return explicit(::new T{FORWARD(param)});
}
int main()
{
auto p1 = make_unique<std::vector<int>>({20});
// creates a container with 1 element initialized with value 20
auto p2 = make_unique<std::vector<int>>(20);
// creates a container with 20 value-initialized elements
auto p3 = make_unique_value<std::vector<int>>({20});
// creates a container with 1 element initialized with value 20
auto p4 = make_unique_value<std::vector<int>>(20);
// compile-time error
}
They provide full coverage of all possible variants of initialization. Try
to implement such generalized makers by means of {}-like "uniform
initialization".
--
------=_Part_5_31873030.1357141988797
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
[Reposting truncated part of the message]<br><br> #define=
FORWARD(x) static_cast<decltype(x)>(x)<br><br> tem=
plate <class T, class... Params><br> &nb=
sp; std::unique_ptr<T> make_unique(Params &&... params)=
<br> {<br> retu=
rn explicit(::new T(FORWARD(params)...));<br> }<br><br>&n=
bsp; template <class T, class U><br> &nb=
sp; std::unique_ptr<T> make_unique_value(U &&am=
p;param)<br> {<br> &nb=
sp; return explicit(::new T{FORWARD(param)});<br> }<br><b=
r> int main()<br> {<br> &nbs=
p; auto p1 =3D make_unique<std::vector<int>=
;>({20});<br> // creates a con=
tainer with 1 element initialized with value 20<br><br> &n=
bsp; auto p2 =3D make_unique<std::vector<int>>=
;(20);<br> // creates a container=
with 20 value-initialized elements<br><br> &n=
bsp; auto p3 =3D make_unique_value<std::vector<int>>({20}=
);<br> // creates a container wit=
h 1 element initialized with value 20<br><br> =
auto p4 =3D make_unique_value<std::vector<int>>(20=
);<br> // compile-time error<br>&=
nbsp; }<br><br>They provide full coverage of all possible varia=
nts of initialization. Try to implement such generalized makers by means of=
{}-like "uniform initialization".<br><br><br><br>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_5_31873030.1357141988797--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Wed, 2 Jan 2013 11:41:37 -0800 (PST)
Raw View
------=_Part_972_11819455.1357155697126
Content-Type: text/plain; charset=ISO-8859-1
It's clear at this point that you're getting pretty far off topic now.
This proposal is about fixing a feature according to its design. That is, I
see a deficiency in an implementation of a design. I believe my
augmentation, as proposed here, would help improve that implementation and
thus come closer to filling the actual designed purpose of the feature.
You're saying that the *design itself*, the *feature*, is fundamentally
wrong-headed.
These are two different discussions. And whether your idea's on enforcing
the distinction between direct and copy initialization has merit or not, *that's
not what this discussion is about*.
This is about making uniform initialization work more like it's *trying*to. Not about saying that the very idea of having a single, uniform method
of initialization is wrong.
--
------=_Part_972_11819455.1357155697126
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
It's clear at this point that you're getting pretty far off topic now.<br><=
br>This proposal is about fixing a feature according to its design. That is=
, I see a deficiency in an implementation of a design. I believe my augment=
ation, as proposed here, would help improve that implementation and thus co=
me closer to filling the actual designed purpose of the feature.<br><br>You=
're saying that the <i>design itself</i>, the <i>feature</i>, is fundamenta=
lly wrong-headed.<br><br>These are two different discussions. And whether y=
our idea's on enforcing the distinction between direct and copy initializat=
ion has merit or not, <i>that's not what this discussion is about</i>.<br><=
br>This is about making uniform initialization work more like it's <i>tryin=
g</i> to. Not about saying that the very idea of having a single, uniform m=
ethod of initialization is wrong.
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_972_11819455.1357155697126--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Thu, 3 Jan 2013 02:40:40 -0800 (PST)
Raw View
------=_Part_337_10076742.1357209640468
Content-Type: text/plain; charset=ISO-8859-1
On Wednesday, January 2, 2013 11:41:37 PM UTC+4, Nicol Bolas wrote:
>
>
> You're saying that the *design itself*, the *feature*, is fundamentally
> wrong-headed.
>
Exactly. Moreover, I think that list-initialization in its current state
should be deprecated (with exception for a few use cases) as soon as
possible. And from my point of view, what you are suggesting here is to go
further in the wrong direction. I don't want to learn more irregular and
pointless rules and read more cryptic code written by others. That's why I
here.
> This is about making uniform initialization work more like it's *trying*to.
OK. How would your suggestion help to write templates like make_unique?
(let's forgot about the distinction between copy-initialization and
direct-initialization for a while)
template <class T, class... Params>
std::unique_ptr<T> make_unique(Params &&... params)
{
return std::unique_ptr<T>(new T{^std::forward<Params>(params)...});
}
int main()
{
auto p = make_unique<std::vector<int>>(10, 1);
// would create a container with 10 elements initialized with value
1
}
What should I do in order to get a sequence of two values: 10 and 1?
--
------=_Part_337_10076742.1357209640468
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Wednesday, January 2, 2013 11:41:37 PM UTC+4, Nicol Bolas wrote:<blockqu=
ote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left=
: 1px #ccc solid;padding-left: 1ex;"><br>You're saying that the <i>design i=
tself</i>, the <i>feature</i>, is fundamentally wrong-headed.<br></blockquo=
te><div><br>Exactly. Moreover, I think that list-initialization in its curr=
ent state should be deprecated (with exception for a few use cases) as soon=
as possible. And from my point of view, what you are suggesting here is to=
go further in the wrong direction. I don't want to learn more irregular an=
d pointless rules and read more cryptic code written by others. That's why =
I here.<br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0=
;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">This is=
about making uniform initialization work more like it's <i>trying</i> to.<=
/blockquote><div><br>OK. How would your suggestion help to write templates =
like make_unique? (let's forgot about the distinction between copy-initiali=
zation and direct-initialization for a while)<br><br> tem=
plate <class T, class... Params><br> &nb=
sp; std::unique_ptr<T> make_unique(Params &&... params)=
<br> {<br> retu=
rn std::unique_ptr<T>(new T{^std::forward<Params>(params)...});=
<br> }<br><br> int main()<br> &nbs=
p; {<br> auto p =3D make_un=
ique<std::vector<int>>(10, 1);<br>  =
; // would create a container with 10 elements initialized with=
value 1<br> }<br><br>What should I do in order to get a =
sequence of two values: 10 and 1?<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_337_10076742.1357209640468--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Thu, 3 Jan 2013 03:17:11 -0800 (PST)
Raw View
------=_Part_393_30733654.1357211831653
Content-Type: text/plain; charset=ISO-8859-1
On Thursday, January 3, 2013 2:40:40 AM UTC-8, Nikolay Ivchenkov wrote:
>
> On Wednesday, January 2, 2013 11:41:37 PM UTC+4, Nicol Bolas wrote:
>>
>>
>> You're saying that the *design itself*, the *feature*, is fundamentally
>> wrong-headed.
>>
>
> Exactly. Moreover, I think that list-initialization in its current state
> should be deprecated (with exception for a few use cases) as soon as
> possible. And from my point of view, what you are suggesting here is to go
> further in the wrong direction. I don't want to learn more irregular and
> pointless rules and read more cryptic code written by others. That's why I
> here.
>
>
>> This is about making uniform initialization work more like it's *trying*to.
>
>
> OK. How would your suggestion help to write templates like make_unique?
> (let's forgot about the distinction between copy-initialization and
> direct-initialization for a while)
>
> template <class T, class... Params>
> std::unique_ptr<T> make_unique(Params &&... params)
> {
> return std::unique_ptr<T>(new T{^std::forward<Params>(params)...});
> }
>
> int main()
> {
> auto p = make_unique<std::vector<int>>(10, 1);
> // would create a container with 10 elements initialized with
> value 1
> }
>
> What should I do in order to get a sequence of two values: 10 and 1?
>
Like this:
make_unique<...>(initializer_list<int>{10, 1});
The only reason the `initializer_list` is there is because the template
argument deduction rules don't allow {} to be deduced from a bare template
type. And I'm not sure if it's a good idea to allow that.
--
------=_Part_393_30733654.1357211831653
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Thursday, January 3, 2013 2:40:40 AM UTC-8, Nikolay Ivchenkov wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">On Wednesday, January 2, 2=
013 11:41:37 PM UTC+4, Nicol Bolas wrote:<blockquote class=3D"gmail_quote" =
style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left=
:1ex"><br>You're saying that the <i>design itself</i>, the <i>feature</i>, =
is fundamentally wrong-headed.<br></blockquote><div><br>Exactly. Moreover, =
I think that list-initialization in its current state should be deprecated =
(with exception for a few use cases) as soon as possible. And from my point=
of view, what you are suggesting here is to go further in the wrong direct=
ion. I don't want to learn more irregular and pointless rules and read more=
cryptic code written by others. That's why I here.<br> </div><blockqu=
ote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1=
px #ccc solid;padding-left:1ex">This is about making uniform initialization=
work more like it's <i>trying</i> to.</blockquote><div><br>OK. How would y=
our suggestion help to write templates like make_unique? (let's forgot abou=
t the distinction between copy-initialization and direct-initialization for=
a while)<br><br> template <class T, class... Params&g=
t;<br> std::unique_ptr<T> m=
ake_unique(Params &&... params)<br> {<br> &n=
bsp; return std::unique_ptr<T>(new T{^s=
td::forward<Params>(<wbr>params)...});<br> }<br><br=
> int main()<br> {<br>  =
; auto p =3D make_unique<std::vector<int>&=
gt;(<wbr>10, 1);<br> // would cre=
ate a container with 10 elements initialized with value 1<br> &n=
bsp; }<br><br>What should I do in order to get a sequence of two values: 10=
and 1?<br></div></blockquote><div><br>Like this:<br><br><div class=3D"pret=
typrint" style=3D"background-color: rgb(250, 250, 250); border-color: rgb(1=
87, 187, 187); border-style: solid; border-width: 1px; word-wrap: break-wor=
d;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span style=
=3D"color: #000;" class=3D"styled-by-prettify">make_unique</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify"><...>(</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify">initializer_list</span><s=
pan style=3D"color: #080;" class=3D"styled-by-prettify"><int></span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span styl=
e=3D"color: #066;" class=3D"styled-by-prettify">10</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=
=3D"styled-by-prettify">1</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">});</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br></span></div></code></div><br>The only reason the `initializer_=
list` is there is because the template argument deduction rules don't allow=
{} to be deduced from a bare template type. And I'm not sure if it's a goo=
d idea to allow that.<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_393_30733654.1357211831653--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Fri, 4 Jan 2013 12:04:51 -0800 (PST)
Raw View
------=_Part_108_29135890.1357329891539
Content-Type: text/plain; charset=ISO-8859-1
On Thursday, January 3, 2013 3:17:11 PM UTC+4, Nicol Bolas wrote:
> OK. How would your suggestion help to write templates like make_unique?
>> (let's forgot about the distinction between copy-initialization and
>> direct-initialization for a while)
>>
>> template <class T, class... Params>
>> std::unique_ptr<T> make_unique(Params &&... params)
>> {
>> return std::unique_ptr<T>(new
>> T{^std::forward<Params>(params)...});
>> }
>>
>> int main()
>> {
>> auto p = make_unique<std::vector<int>>(10, 1);
>> // would create a container with 10 elements initialized with
>> value 1
>> }
>>
>> What should I do in order to get a sequence of two values: 10 and 1?
>>
>
> Like this:
>
> make_unique<...>(initializer_list<int>{10, 1});
>
That's verbose. Initialization with parentheses and list-initialization can
already be roughly combined in a similar way in a library tool:
http://liveworkspace.org/code/1TOPrl$0
A core language construct could have some advantages (such as improved
compile-time diagnostics, brevity, flexibility, and reduced translation
time) over such a library solution, but It would look like a half measure
that actually does not solve the most important initialization-related
issues (brevity + readability + diagnostics, efficiency). By the way, if it
will be accepted, when should we stop? I can imagine people who would like
to use ()-like initialization with checking for narrowing conversions.
Should the language have something like (^arg_list)-wise syntax for that?
Note that {^arg_list} is not a superior alternative, because it's too
common. We already have an example of a multipurpose facility - C-style
cast. It can perform the same conversions as static_cast, reinterpret_cast
and const_cast. Very "uniform" thing, right? So why should we ever prefer
static_cast, reinterpret_cast or const_cast? That's because they give us an
ability to express our intention more precisely. It seems that this simple
idea was completely forgotten when the concept of list-initialization was
under development.
> The only reason the `initializer_list` is there is because the template
> argument deduction rules don't allow {} to be deduced from a bare template
> type. And I'm not sure if it's a good idea to allow that.
>
I think that it's still possible to introduce initializer lists with
expression semantics:
template <class T, class... Params>
std::unique_ptr<T> make_unique(Params &&... params)
{ return : (new T(FORWARD(params)...)); }
// return : (arg_list) is another possible extension for
direct-initialization
struct A
{
int x, y;
};
int main()
{
auto p1 = make_unique<std::vector<int>>(10, 1);
// would create a container with 10 elements initialized with value
1
auto p2 = make_unique<std::vector<int>>(~{10, 1}); // ~{10, 1} is a
prvalue
// would create a container with 2 elements initialized with values
10 and 1
auto p3 = make_unique<A>(~{1, 2});
// would create an object of type A where x = 1 and y = 2
auto p4 = make_unique<A>(1, 2);
// would be an error
}
--
------=_Part_108_29135890.1357329891539
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Thursday, January 3, 2013 3:17:11 PM UTC+4, Nicol Bolas wrote:<br><block=
quote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-le=
ft: 1px #ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1=
ex"><div>OK. How would your suggestion help to write templates like make_un=
ique? (let's forgot about the distinction between copy-initialization and d=
irect-initialization for a while)<br><br> template <cl=
ass T, class... Params><br> st=
d::unique_ptr<T> make_unique(Params &&... params)<br> &n=
bsp; {<br> return std::uniq=
ue_ptr<T>(new T{^std::forward<Params>(<wbr>params)...});<br>&nb=
sp; }<br><br> int main()<br>  =
; {<br> auto p =3D make_unique<=
;std::vector<int>>(<wbr>10, 1);<br> &=
nbsp; // would create a container with 10 elements initialized with v=
alue 1<br> }<br><br>What should I do in order to get a se=
quence of two values: 10 and 1?<br></div></blockquote><div><br>Like this:<b=
r><br><div style=3D"background-color:rgb(250,250,250);border-color:rgb(187,=
187,187);border-style:solid;border-width:1px;word-wrap:break-word"><code><d=
iv><span style=3D"color:#000">make_unique</span><span style=3D"color:#660">=
<...>(</span><span style=3D"color:#000">initializer_<wbr>list</span><=
span style=3D"color:#080"><int></span><span style=3D"color:#660">{</s=
pan><span style=3D"color:#066">10</span><span style=3D"color:#660">,</span>=
<span style=3D"color:#000"> </span><span style=3D"color:#066">1</span><span=
style=3D"color:#660">});</span><span style=3D"color:#000"><br></span></div=
></code></div></div></blockquote><div><br>That's verbose. Initialization wi=
th parentheses and list-initialization can already be roughly combined in =
a similar way in a library tool:<br>http://liveworkspace.org/code/1TOPrl$0<=
br><br>A core language construct could have some advantages (such as improv=
ed compile-time diagnostics, brevity, flexibility, and reduced translation =
time) over such a library solution, but It would look like a half measure t=
hat actually does not solve the most important initialization-related issue=
s (brevity + readability + diagnostics, efficiency). By the way, if it will=
be accepted, when should we stop? I can imagine people who would like to u=
se ()-like initialization with checking for narrowing conversions. Should t=
he language have something like (^arg_list)-wise syntax for that? Note that=
{^arg_list} is not a superior alternative, because it's too common. We alr=
eady have an example of a multipurpose facility - C-style cast. It can perf=
orm the same conversions as static_cast, reinterpret_cast and const_cast. V=
ery "uniform" thing, right? So why should we ever prefer static_cast, reint=
erpret_cast or const_cast? That's because they give us an ability to expres=
s our intention more precisely. It seems that this simple idea was complete=
ly forgotten when the concept of list-initialization was under development.=
<br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin=
-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>The only =
reason the `initializer_list` is there is because the template argument ded=
uction rules don't allow {} to be deduced from a bare template type. And I'=
m not sure if it's a good idea to allow that.<br></div></blockquote><div><b=
r>I think that it's still possible to introduce initializer lists with expr=
ession semantics:<br><br> template <class T, class... =
Params><br> std::unique_ptr<=
;T> make_unique(Params &&... params)<br> =
{ return : (new T(FORWARD(params=
)...)); }<br> &n=
bsp; // return : (arg_list) is another possible extension for direct-initia=
lization<br><br> struct A<br> {<br>&nbs=
p; int x, y;<br> };<b=
r><br> int main()<br> {<br> =
auto p1 =3D make_unique<std::vector<in=
t>>(10, 1);<br> // would cr=
eate a container with 10 elements initialized with value 1<br><br> &nb=
sp; auto p2 =3D make_unique<std::vector<=
;int>>(~{10, 1}); // ~{10, 1} is a prvalue<br>  =
; // would create a container with 2 elements initialized=
with values 10 and 1<br><br> aut=
o p3 =3D make_unique<A>(~{1, 2});<br> &n=
bsp; // would create an object of type A where x =3D 1 and y =3D 2<br=
><br> auto p4 =3D make_unique<=
A>(1, 2);<br> // would be an e=
rror<br> }<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_108_29135890.1357329891539--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Fri, 4 Jan 2013 12:27:02 -0800 (PST)
Raw View
------=_Part_1495_3400510.1357331222077
Content-Type: text/plain; charset=ISO-8859-1
On Friday, January 4, 2013 12:04:51 PM UTC-8, Nikolay Ivchenkov wrote:
>
> On Thursday, January 3, 2013 3:17:11 PM UTC+4, Nicol Bolas wrote:
>
>> OK. How would your suggestion help to write templates like make_unique?
>>> (let's forgot about the distinction between copy-initialization and
>>> direct-initialization for a while)
>>>
>>> template <class T, class... Params>
>>> std::unique_ptr<T> make_unique(Params &&... params)
>>> {
>>> return std::unique_ptr<T>(new
>>> T{^std::forward<Params>(params)...});
>>> }
>>>
>>> int main()
>>> {
>>> auto p = make_unique<std::vector<int>>(10, 1);
>>> // would create a container with 10 elements initialized with
>>> value 1
>>> }
>>>
>>> What should I do in order to get a sequence of two values: 10 and 1?
>>>
>>
>> Like this:
>>
>> make_unique<...>(initializer_list<int>{10, 1});
>>
>
> That's verbose. Initialization with parentheses and list-initialization
> can already be roughly combined in a similar way in a library tool:
> http://liveworkspace.org/code/1TOPrl$0
>
Which... only works in that one instance. And it specifically picks
constructors over list-initialization, and therefore it works exactly like
using the {:} syntax I'm suggesting.
You're talking about a very specific problem: template type deduction of
initializer lists. That's not the problem under discussion for this
proposal.
Also, you could much more easily resolve this by simply adding an overload
for make_unique:
template<typename Ret, typename T>
std::unique_ptr<Ret> make_unique(std::initailizer_list<T> list)
{
return {new Ret{list}};
}
This will allow template argument deduction to attempt to deduce a naked
braced-init-list as an initializer_list, thus deducing the type of that
initializer list. Which will then be passed to Ret's constructor as an
argument.
A core language construct could have some advantages (such as improved
> compile-time diagnostics, brevity, flexibility, and reduced translation
> time) over such a library solution, but It would look like a half measure
> that actually does not solve the most important initialization-related
> issues (brevity + readability + diagnostics, efficiency). By the way, if it
> will be accepted, when should we stop? I can imagine people who would like
> to use ()-like initialization with checking for narrowing conversions.
> Should the language have something like (^arg_list)-wise syntax for that?
> Note that {^arg_list} is not a superior alternative, because it's too
> common. We already have an example of a multipurpose facility - C-style
> cast. It can perform the same conversions as static_cast, reinterpret_cast
> and const_cast. Very "uniform" thing, right? So why should we ever prefer
> static_cast, reinterpret_cast or const_cast? That's because they give us an
> ability to express our intention more precisely. It seems that this simple
> idea was completely forgotten when the concept of list-initialization was
> under development.
>
Allow me to reiterate:
*Take that elsewhere.
*This thread is about resolving a *specific problem* with uniform
initialization. If you don't like the uniformity of uniform initialization,
that's your prerogative. But *this isn't the place to talk about that.*This thread is about making uniform initialization work more like it is
designed to, not *redesigning* it.
--
------=_Part_1495_3400510.1357331222077
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Friday, January 4, 2013 12:04:51 PM UTC-8, Nikolay Ivchenkov wro=
te:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;">On Thursday, January 3, 201=
3 3:17:11 PM UTC+4, Nicol Bolas wrote:<br><blockquote class=3D"gmail_quote"=
style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-lef=
t:1ex"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8e=
x;border-left:1px #ccc solid;padding-left:1ex"><div>OK. How would your sugg=
estion help to write templates like make_unique? (let's forgot about the di=
stinction between copy-initialization and direct-initialization for a while=
)<br><br> template <class T, class... Params><br>&n=
bsp; std::unique_ptr<T> make_uniq=
ue(Params &&... params)<br> {<br> &nbs=
p; return std::unique_ptr<T>(new T{^std::forw=
ard<Params>(<wbr>params)...});<br> }<br><br> &=
nbsp; int main()<br> {<br> &=
nbsp; auto p =3D make_unique<std::vector<int>>(<wbr=
>10, 1);<br> // would create a co=
ntainer with 10 elements initialized with value 1<br> }<b=
r><br>What should I do in order to get a sequence of two values: 10 and 1?<=
br></div></blockquote><div><br>Like this:<br><br><div style=3D"background-c=
olor:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;bord=
er-width:1px;word-wrap:break-word"><code><div><span style=3D"color:#000">ma=
ke_unique</span><span style=3D"color:#660"><...>(</span><span style=
=3D"color:#000">initializer_<wbr>list</span><span style=3D"color:#080"><=
int></span><span style=3D"color:#660">{</span><span style=3D"color:#066"=
>10</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> </=
span><span style=3D"color:#066">1</span><span style=3D"color:#660">});</spa=
n><span style=3D"color:#000"><br></span></div></code></div></div></blockquo=
te><div><br>That's verbose. Initialization with parentheses and list-initia=
lization can already be roughly combined in a similar way in a library too=
l:<br><a href=3D"http://liveworkspace.org/code/1TOPrl$0" target=3D"_blank">=
http://liveworkspace.org/code/<wbr>1TOPrl$0</a><br></div></blockquote><div>=
<br>Which... only works in that one instance. And it specifically picks con=
structors over list-initialization, and therefore it works exactly like usi=
ng the {:} syntax I'm suggesting.<br><br>You're talking about a very specif=
ic problem: template type deduction of initializer lists. That's not the pr=
oblem under discussion for this proposal.<br><br>Also, you could much more =
easily resolve this by simply adding an overload for make_unique:<br><br><d=
iv class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); bor=
der-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; word=
-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprin=
t"><span style=3D"color: #008;" class=3D"styled-by-prettify">template</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span=
style=3D"color: #008;" class=3D"styled-by-prettify">typename</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #606;" class=3D"styled-by-prettify">Ret</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"sty=
led-by-prettify">typename</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> T</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">></span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
><br>std</span><span style=3D"color: #660;" class=3D"styled-by-prettify">::=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify">unique_ptr=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify"><</span=
><span style=3D"color: #606;" class=3D"styled-by-prettify">Ret</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">></span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> make_unique</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify">std</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">initailizer_list</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify"><</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">T</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">></span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> list</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"><br> </span><=
span style=3D"color: #008;" class=3D"styled-by-prettify">return</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #=
008;" class=3D"styled-by-prettify">new</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> </span><span style=3D"color: #606;" class=3D"s=
tyled-by-prettify">Ret</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y">list</span><span style=3D"color: #660;" class=3D"styled-by-prettify">}};=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">}</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br></span></div></code><=
/div><br>This will allow template argument deduction to attempt to deduce a=
naked braced-init-list as an initializer_list, thus deducing the type of t=
hat initializer list. Which will then be passed to Ret's constructor as an =
argument.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0=
;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>A =
core language construct could have some advantages (such as improved compil=
e-time diagnostics, brevity, flexibility, and reduced translation time) ove=
r such a library solution, but It would look like a half measure that actua=
lly does not solve the most important initialization-related issues (brevit=
y + readability + diagnostics, efficiency). By the way, if it will be accep=
ted, when should we stop? I can imagine people who would like to use ()-lik=
e initialization with checking for narrowing conversions. Should the langua=
ge have something like (^arg_list)-wise syntax for that? Note that {^arg_li=
st} is not a superior alternative, because it's too common. We already have=
an example of a multipurpose facility - C-style cast. It can perform the s=
ame conversions as static_cast, reinterpret_cast and const_cast. Very "unif=
orm" thing, right? So why should we ever prefer static_cast, reinterpret_ca=
st or const_cast? That's because they give us an ability to express our int=
ention more precisely. It seems that this simple idea was completely forgot=
ten when the concept of list-initialization was under development.<br></div=
></blockquote><div><br>Allow me to reiterate:<br><br><i>Take that elsewhere=
..<br><br></i>This thread is about resolving a <i>specific problem</i> with =
uniform initialization. If you don't like the uniformity of uniform initial=
ization, that's your prerogative. But <i>this isn't the place to talk about=
that.</i> This thread is about making uniform initialization work more lik=
e it is designed to, not <i>redesigning</i> it.<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1495_3400510.1357331222077--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Fri, 4 Jan 2013 14:39:50 -0800 (PST)
Raw View
------=_Part_1207_8531324.1357339190147
Content-Type: text/plain; charset=ISO-8859-1
On Saturday, January 5, 2013 12:27:02 AM UTC+4, Nicol Bolas wrote:
>
> Initialization with parentheses and list-initialization can already be
>> roughly combined in a similar way in a library tool:
>> http://liveworkspace.org/code/1TOPrl$0
>>
>
> Which... only works in that one instance.
>
new-expressions can be used to create objects on a stack/automatic memory.
Such objects will never be treated as temporary though.
> And it specifically picks constructors over list-initialization, and
> therefore it works exactly like using the {:} syntax I'm suggesting.
>
According to your description, in your case an aggregate initialization may
take precedence over a valid ()-wise direct-initialization with other
meaning. But it seems that that would happen in exotic cases. I could
disallow every list-initialization that is not an aggregate initialization
if std::is_aggregate would be available.
> You're talking about a very specific problem: template type deduction of
> initializer lists. That's not the problem under discussion for this
> proposal.
>
A resolution of such a "very specific problem" may conflict with your
proposal or (most likely) be a superior solution for actual problems that
your proposal could solve. I don't think that it would be wise to
concentrate our attention on a single issue and ignore others, because
suggestions for their resolution may potentially interact with each other.
> Also, you could much more easily resolve this by simply adding an overload
> for make_unique:
>
> template<typename Ret, typename T>
> std::unique_ptr<Ret> make_unique(std::initailizer_list<T> list)
> {
> return {new Ret{list}};
> }
>
> This will allow template argument deduction to attempt to deduce a naked
> braced-init-list as an initializer_list, thus deducing the type of that
> initializer list. Which will then be passed to Ret's constructor as an
> argument.
>
Such a resolution is not scalable. What if I want to pass 2 or more
arguments to the constructor?
struct X
{
X(int, std::initializer_list<int>);
};
--
------=_Part_1207_8531324.1357339190147
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Saturday, January 5, 2013 12:27:02 AM UTC+4, Nicol Bolas wrote:<blockquo=
te class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left:=
1px #ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div>Initialization with parentheses and list-initialization can already =
be roughly combined in a similar way in a library tool:<br><a href=3D"http:=
//liveworkspace.org/code/1TOPrl$0" target=3D"_blank">http://liveworkspace.o=
rg/code/<wbr>1TOPrl$0</a><br></div></blockquote><div><br>Which... only work=
s in that one instance.</div></blockquote><div><br>new-expressions can be u=
sed to create objects on a stack/automatic memory. Such objects will never =
be treated as temporary though.<br> </div><blockquote class=3D"gmail_q=
uote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pad=
ding-left: 1ex;"><div> And it specifically picks constructors over list-ini=
tialization, and therefore it works exactly like using the {:} syntax I'm s=
uggesting.<br></div></blockquote><div><br>According to your description, in=
your case an aggregate initialization may take precedence over a valid ()-=
wise direct-initialization with other meaning. But it seems that that would=
happen in exotic cases. I could disallow every list-initialization that is=
not an aggregate initialization if std::is_aggregate would be available.<b=
r> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-l=
eft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>You're talk=
ing about a very specific problem: template type deduction of initializer l=
ists. That's not the problem under discussion for this proposal.<br></div><=
/blockquote><div><br>A resolution of such a "very specific problem" may con=
flict with your proposal or (most likely) be a superior solution for actual=
problems that your proposal could solve. I don't think that it would be wi=
se to concentrate our attention on a single issue and ignore others, becaus=
e suggestions for their resolution may potentially interact with each other=
..<br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>Also, yo=
u could much more easily resolve this by simply adding an overload for make=
_unique:<br><br><div style=3D"background-color:rgb(250,250,250);border-colo=
r:rgb(187,187,187);border-style:solid;border-width:1px;word-wrap:break-word=
"><code><div><span style=3D"color:#008">template</span><span style=3D"color=
:#660"><</span><span style=3D"color:#008">typename</span><span style=3D"=
color:#000"> </span><span style=3D"color:#606">Ret</span><span style=3D"col=
or:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color:#0=
08">typename</span><span style=3D"color:#000"> T</span><span style=3D"color=
:#660">></span><span style=3D"color:#000"><br>std</span><span style=3D"c=
olor:#660">::</span><span style=3D"color:#000">unique_ptr</span><span style=
=3D"color:#660"><</span><span style=3D"color:#606">Ret</span><span style=
=3D"color:#660">></span><span style=3D"color:#000"> make_unique</span><s=
pan style=3D"color:#660">(</span><span style=3D"color:#000">std</span><span=
style=3D"color:#660">::</span><span style=3D"color:#000">initailizer_<wbr>=
list</span><span style=3D"color:#660"><</span><span style=3D"color:#000"=
>T</span><span style=3D"color:#660">></span><span style=3D"color:#000"> =
list</span><span style=3D"color:#660">)</span><span style=3D"color:#000"><b=
r></span><span style=3D"color:#660">{</span><span style=3D"color:#000"><br>=
</span><span style=3D"color:#008">return</span><span style=3D"color:=
#000"> </span><span style=3D"color:#660">{</span><span style=3D"color:#008"=
>new</span><span style=3D"color:#000"> </span><span style=3D"color:#606">Re=
t</span><span style=3D"color:#660">{</span><span style=3D"color:#000">list<=
/span><span style=3D"color:#660">}};</span><span style=3D"color:#000"><br><=
/span><span style=3D"color:#660">}</span><span style=3D"color:#000"><br></s=
pan></div></code></div><br>This will allow template argument deduction to a=
ttempt to deduce a naked braced-init-list as an initializer_list, thus dedu=
cing the type of that initializer list. Which will then be passed to Ret's =
constructor as an argument.<br></div></blockquote><div><br>Such a resolutio=
n is not scalable. What if I want to pass 2 or more arguments to the constr=
uctor?<br><br> struct X<br> {<br> =
X(int, std::initializer_list<int>=
;);<br> };<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1207_8531324.1357339190147--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Fri, 4 Jan 2013 15:43:54 -0800 (PST)
Raw View
------=_Part_1715_28778500.1357343034937
Content-Type: text/plain; charset=ISO-8859-1
On Friday, January 4, 2013 2:39:50 PM UTC-8, Nikolay Ivchenkov wrote:
>
> On Saturday, January 5, 2013 12:27:02 AM UTC+4, Nicol Bolas wrote:
>>
>> Initialization with parentheses and list-initialization can already be
>>> roughly combined in a similar way in a library tool:
>>> http://liveworkspace.org/code/1TOPrl$0
>>>
>>
>> Which... only works in that one instance.
>>
>
> new-expressions can be used to create objects on a stack/automatic memory.
> Such objects will never be treated as temporary though.
>
>
>> And it specifically picks constructors over list-initialization, and
>> therefore it works exactly like using the {:} syntax I'm suggesting.
>>
>
> According to your description, in your case an aggregate initialization
> may take precedence over a valid ()-wise direct-initialization with other
> meaning.
>
When? If an object has a constructor, then it is not an aggregate.
Therefore, aggregate initialization is not possible. So for any particular
T, you will either use aggregate initialization or call some form of
constructor. My proposal is quite clear on this: the only difference
between {:} and {} is which constructors take precedence; they behave
exactly the same otherwise. There is no conflict.
The only time when it is unclear exactly what {} initialization will do is
when choosing which constructors to call. In all other cases, it is
completely unambiguous.
But it seems that that would happen in exotic cases. I could disallow every
> list-initialization that is not an aggregate initialization if
> std::is_aggregate would be available.
>
>
>> You're talking about a very specific problem: template type deduction of
>> initializer lists. That's not the problem under discussion for this
>> proposal.
>>
>
> A resolution of such a "very specific problem" may conflict with your
> proposal or (most likely) be a superior solution for actual problems that
> your proposal could solve. I don't think that it would be wise to
> concentrate our attention on a single issue and ignore others, because
> suggestions for their resolution may potentially interact with each other.
>
There are only two possible solutions to this:
1: Define that a braced-init-list is deduced in a template as an
initializer_list<T>, for some deduced type T based on some arbitrary rules.
2: Define that a braced-init-list is deduced as some completely new object
with rules and behavior which is somehow magically able to be converted
into perfectly-forwarded braced-init-list construction parameters on-demand.
Neither such option interferes in any way with this proposal. Currently, a
braced-init-list is not deduced at all, and my suggestion changes nothing
about that. If the committee later wants to add some rules for
braced-init-list deduction, my proposal won't change that determination one
way or the other.
>
>
>> Also, you could much more easily resolve this by simply adding an
>> overload for make_unique:
>>
>> template<typename Ret, typename T>
>> std::unique_ptr<Ret> make_unique(std::initailizer_list<T> list)
>> {
>> return {new Ret{list}};
>> }
>>
>> This will allow template argument deduction to attempt to deduce a naked
>> braced-init-list as an initializer_list, thus deducing the type of that
>> initializer list. Which will then be passed to Ret's constructor as an
>> argument.
>>
>
> Such a resolution is not scalable. What if I want to pass 2 or more
> arguments to the constructor?
>
> struct X
> {
> X(int, std::initializer_list<int>);
> };
>
You keep trying to turn this into a general discussion about uniform
initialization and such. I want to keep it focused on the problem I'm
trying to solve: making uniform initialization more reasonably usable by
fixing one of the biggest downsides of its use: the fact that it prefers
initializer_list constructors over the others. *That's all.*
Are there other non-uniformities? Yes. Are there other places where fixes
could happen? Yes. But this is not a suggestion to fix every problem with
uniform initialization. This is not a thread to discuss every possible
problem with uniform initialization. It's a proposal to fix *one specific
problem*, to make uniform initialization work better. Stop trying to expand
it into something too big to go into C++14. If you want to talk about some
kind of perfect forwarding for uniform initialization, fine; start a thread
on that.
But please stop derailing this thread with issues that have *nothing to do*with the proposal in question.
--
------=_Part_1715_28778500.1357343034937
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Friday, January 4, 2013 2:39:50 PM UTC-8, Nikolay Ivchenkov wrot=
e:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;">On Saturday, January 5, 2013=
12:27:02 AM UTC+4, Nicol Bolas wrote:<blockquote class=3D"gmail_quote" sty=
le=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1e=
x"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;bo=
rder-left:1px #ccc solid;padding-left:1ex"><div>Initialization with parenth=
eses and list-initialization can already be roughly combined in a similar =
way in a library tool:<br><a href=3D"http://liveworkspace.org/code/1TOPrl$0=
" target=3D"_blank">http://liveworkspace.org/code/<wbr>1TOPrl$0</a><br></di=
v></blockquote><div><br>Which... only works in that one instance.</div></bl=
ockquote><div><br>new-expressions can be used to create objects on a stack/=
automatic memory. Such objects will never be treated as temporary though.<b=
r> </div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-le=
ft:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div> And it specific=
ally picks constructors over list-initialization, and therefore it works ex=
actly like using the {:} syntax I'm suggesting.<br></div></blockquote><div>=
<br>According to your description, in your case an aggregate initialization=
may take precedence over a valid ()-wise direct-initialization with other =
meaning.</div></blockquote><div><br>When? If an object has a constructor, t=
hen it is not an aggregate. Therefore, aggregate initialization is not poss=
ible. So for any particular T, you will either use aggregate initialization=
or call some form of constructor. My proposal is quite clear on this: the =
only difference between {:} and {} is which constructors take precedence; t=
hey behave exactly the same otherwise. There is no conflict.<br><br>The onl=
y time when it is unclear exactly what {} initialization will do is when ch=
oosing which constructors to call. In all other cases, it is completely una=
mbiguous.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0=
;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>Bu=
t it seems that that would happen in exotic cases. I could disallow every l=
ist-initialization that is not an aggregate initialization if std::is_aggre=
gate would be available.<br> </div><blockquote class=3D"gmail_quote" s=
tyle=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:=
1ex"><div>You're talking about a very specific problem: template type deduc=
tion of initializer lists. That's not the problem under discussion for this=
proposal.<br></div></blockquote><div><br>A resolution of such a "very spec=
ific problem" may conflict with your proposal or (most likely) be a superio=
r solution for actual problems that your proposal could solve. I don't thin=
k that it would be wise to concentrate our attention on a single issue and =
ignore others, because suggestions for their resolution may potentially int=
eract with each other.<br></div></blockquote><div><br>There are only two po=
ssible solutions to this:<br><br>1: Define that a braced-init-list is deduc=
ed in a template as an initializer_list<T>, for some deduced type T b=
ased on some arbitrary rules.<br>2: Define that a braced-init-list is deduc=
ed as some completely new object with rules and behavior which is somehow m=
agically able to be converted into perfectly-forwarded braced-init-list con=
struction parameters on-demand.<br><br>Neither such option interferes in an=
y way with this proposal. Currently, a braced-init-list is not deduced at a=
ll, and my suggestion changes nothing about that. If the committee later wa=
nts to add some rules for braced-init-list deduction, my proposal won't cha=
nge that determination one way or the other.<br> </div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #=
ccc solid;padding-left: 1ex;"><div> </div><blockquote class=3D"gmail_q=
uote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;paddin=
g-left:1ex"><div>Also, you could much more easily resolve this by simply ad=
ding an overload for make_unique:<br><br><div style=3D"background-color:rgb=
(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-width=
:1px;word-wrap:break-word"><code><div><span style=3D"color:#008">template</=
span><span style=3D"color:#660"><</span><span style=3D"color:#008">typen=
ame</span><span style=3D"color:#000"> </span><span style=3D"color:#606">Ret=
</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> </spa=
n><span style=3D"color:#008">typename</span><span style=3D"color:#000"> T</=
span><span style=3D"color:#660">></span><span style=3D"color:#000"><br>s=
td</span><span style=3D"color:#660">::</span><span style=3D"color:#000">uni=
que_ptr</span><span style=3D"color:#660"><</span><span style=3D"color:#6=
06">Ret</span><span style=3D"color:#660">></span><span style=3D"color:#0=
00"> make_unique</span><span style=3D"color:#660">(</span><span style=3D"co=
lor:#000">std</span><span style=3D"color:#660">::</span><span style=3D"colo=
r:#000">initailizer_<wbr>list</span><span style=3D"color:#660"><</span><=
span style=3D"color:#000">T</span><span style=3D"color:#660">></span><sp=
an style=3D"color:#000"> list</span><span style=3D"color:#660">)</span><spa=
n style=3D"color:#000"><br></span><span style=3D"color:#660">{</span><span =
style=3D"color:#000"><br> </span><span style=3D"color:#008">return</s=
pan><span style=3D"color:#000"> </span><span style=3D"color:#660">{</span><=
span style=3D"color:#008">new</span><span style=3D"color:#000"> </span><spa=
n style=3D"color:#606">Ret</span><span style=3D"color:#660">{</span><span s=
tyle=3D"color:#000">list</span><span style=3D"color:#660">}};</span><span s=
tyle=3D"color:#000"><br></span><span style=3D"color:#660">}</span><span sty=
le=3D"color:#000"><br></span></div></code></div><br>This will allow templat=
e argument deduction to attempt to deduce a naked braced-init-list as an in=
itializer_list, thus deducing the type of that initializer list. Which will=
then be passed to Ret's constructor as an argument.<br></div></blockquote>=
<div><br>Such a resolution is not scalable. What if I want to pass 2 or mor=
e arguments to the constructor?<br><br> struct X<br> =
; {<br> X(int, std::i=
nitializer_list<int>);<br> };<br></div></blockquote=
><div><br>You keep trying to turn this into a general discussion about unif=
orm initialization and such. I want to keep it focused on the problem I'm t=
rying to solve: making uniform initialization more reasonably usable by fix=
ing one of the biggest downsides of its use: the fact that it prefers initi=
alizer_list constructors over the others. <i>That's all.</i><br><br>Are the=
re other non-uniformities? Yes. Are there other places where fixes could ha=
ppen? Yes. But this is not a suggestion to fix every problem with uniform i=
nitialization. This is not a thread to discuss every possible problem with =
uniform initialization. It's a proposal to fix <i>one specific problem</i>,=
to make uniform initialization work better. Stop trying to expand it into =
something too big to go into C++14. If you want to talk about some kind of =
perfect forwarding for uniform initialization, fine; start a thread on that=
..<br><br>But please stop derailing this thread with issues that have <i>not=
hing to do</i> with the proposal in question.<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1715_28778500.1357343034937--
.
Author: Jeffrey Yasskin <jyasskin@googlers.com>
Date: Fri, 4 Jan 2013 16:04:10 -0800
Raw View
I haven't read the whole thread. Sorry if some of this has been
covered elsewhere.
On Sun, Dec 30, 2012 at 1:49 PM, Nicol Bolas <jmckesson@gmail.com> wrote:
> ...
> Because uniform initialization syntax always prefers initializer list
> constructors if one is available that would fit the braced-init-list. Thi=
s
> is a consequence of uniform initialization syntax using the same syntax a=
s
> initializer lists: the braced-init-list. And since
> std::vector<int>::vector(std::initializer_list<int>) matches the
> braced-init-list ({20}), it will be preferred over
> std::vector<int>::vector(std::vector<int>::size_type)
>
> This is a problem because there is no way to get at the size_type
> constructor via uniform initialization. There is no syntax that we can
> employ which will cause the conflicting initializer_list constructor to b=
e
> ignored or to do anything else that would allow us to get at a different =
set
> of constructors.
>
> Now, this may seem like a rather unimportant issue. After all, if I know
> that I have to use constructor initialization with vector<int>, then I ca=
n
> simply do that. But consider code that is generic on the vector's type:
>
> template<typename T>
> std::vector<T> MakeVector()
> {
> return std::vector<T>{20};
> }
When you want to call an algorithmic constructor (i.e. one where the
constructor arguments don't represent the values placed into the
constructed object), use the non-brace format, "std::vector<T>(20)".
Now that we have move constructors and common NRVO support, I would
name that constructor something like
"std::vector<T>::make_repeated(20)", but I wouldn't want to push for a
redundant constructor now.
> By all rights, this code should always do the same thing: return a vector
> containing 20 value-initialized elements. But it does not. MakeVector<int=
>()
> will return a vector containing exactly one element.
>
> This is of much greater concern when dealing with more intricate template=
s.
> Consider the following trivial template function:
>
> template<typename T>
> T Process()
> {
> T t{};
> //do stuff with t;
> return T{t};
> }
>
> This function creates a temporary, does some processing, and returns a co=
py
> of it. This function requires that T be DefaultConstructible and
> CopyConstructible, in addition to whatever =93do stuff with t=94 requires=
..
>
> The problem is the last line. This line may violate the concept constrain=
t.
> Why? Because there is no guarantee that T does not have an initializer_li=
st
> constructor that can match with a T. For an example of such a class,
> consider std::vector<std::function<void()>> as our T.
Good point; I wouldn't have guessed that vector{same_type_vector}
could (attempt to) construct a 1-element vector instead of copying the
vector. That said, it can be fixed by using T(t) when intentionally
calling a copy constructor.
Interestingly, libc++ uses SFINAE to exclude non-callable parameters
from the std::function constructor, so this bug can't happen there.
That may violate the standard, which uses Requires instead of "shall
not participate in overload resolution".
> The problem is that std::function has a non-explicit constructor that can
> take any type that is CopyConstructible. And std::vector<std::function> i=
s
> CopyConstructible. Therefore, this will call the initializer_list
> constructor. But the template function should not be calling the initiali=
zer
> list constructor; it's not part of the allowed interface to T. Therefore,
> Process violates the concept constraint, through no fault on the user's
> part.
>
> ...
>
> Design Overview
>
> The idea is quite simple. We will divide braced-init-list up into two
> variation: list-braced-init-list and constr-braced-init-list. Most of the
> text will remain the exact same, as they have almost identical behavior.
>
> The difference is that 13.3.1.7's list initialization overload resolution
> rules will behave differently. list-braced-init-list initialization will
> work exactly as it does. constr-braced-init-list will work opposite to th=
e
> current way. That is, it will check non-initializer_list constructors fir=
st,
> then go to the initializer_list ones if no matching constructors are foun=
d.
> All other uses will work identically; you can use these for aggregate
> initialization and so forth just as before.
>
> The big issue is how constr-braced-init-lists are defined in the grammar.=
It
> should look like this:
>
> {^ ... }
>
> The =93{=94 token followed by the =93^=94 token is what distinguishes the
> constr-braced-init-list from a list-braced-init-list.
To make construction use more uniform syntax than the two we have, you
want to add a third syntax to construct things? How does that make
sense?
> ...
> Currently, std::allocator_traits::construct is defined in terms of callin=
g
> new(/*stuff*/) T(std::forward<Args>(args)...). That will call constructor=
s,
> but it will only call constructors. If we have a simple struct that could
> use aggregate initialization, we cannot use, for example, emplace on it:
Arguably, it's also a bug that foo.emplace() can't append a
vector<int> containing just {20}, but that isn't fixed by your
proposal.
> ...
Jeffrey
--=20
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Fri, 4 Jan 2013 17:50:49 -0800 (PST)
Raw View
------=_Part_1764_16446875.1357350649543
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Friday, January 4, 2013 4:04:10 PM UTC-8, Jeffrey Yasskin wrote:
>
> I haven't read the whole thread. Sorry if some of this has been=20
> covered elsewhere.=20
> > By all rights, this code should always do the same thing: return a=20
> vector=20
> > containing 20 value-initialized elements. But it does not.=20
> MakeVector<int>()=20
> > will return a vector containing exactly one element.=20
> >=20
> > This is of much greater concern when dealing with more intricate=20
> templates.=20
> > Consider the following trivial template function:=20
> >=20
> > template<typename T>=20
> > T Process()=20
> > {=20
> > T t{};=20
> > //do stuff with t;=20
> > return T{t};=20
> > }=20
> >=20
> > This function creates a temporary, does some processing, and returns a=
=20
> copy=20
> > of it. This function requires that T be DefaultConstructible and=20
> > CopyConstructible, in addition to whatever =93do stuff with t=94 requir=
es.=20
> >=20
> > The problem is the last line. This line may violate the concept=20
> constraint.=20
> > Why? Because there is no guarantee that T does not have an=20
> initializer_list=20
> > constructor that can match with a T. For an example of such a class,=20
> > consider std::vector<std::function<void()>> as our T.=20
>
> Good point; I wouldn't have guessed that vector{same_type_vector}=20
> could (attempt to) construct a 1-element vector instead of copying the=20
> vector. That said, it can be fixed by using T(t) when intentionally=20
> calling a copy constructor.=20
>
That's uniform initialization not being uniform, then, which is exactly the=
=20
problem this is trying to solve. If you can't use {} everywhere, if you=20
have to use () in some cases, then the syntax needs fixing.
Interestingly, libc++ uses SFINAE to exclude non-callable parameters=20
> from the std::function constructor, so this bug can't happen there.=20
> That may violate the standard, which uses Requires instead of "shall=20
> not participate in overload resolution".=20
>
> > The problem is that std::function has a non-explicit constructor that=
=20
> can=20
> > take any type that is CopyConstructible. And std::vector<std::function>=
=20
> is=20
> > CopyConstructible. Therefore, this will call the initializer_list=20
> > constructor. But the template function should not be calling the=20
> initializer=20
> > list constructor; it's not part of the allowed interface to T.=20
> Therefore,=20
> > Process violates the concept constraint, through no fault on the user's=
=20
> > part.=20
> >=20
> > ...=20
> >=20
> > Design Overview=20
> >=20
> > The idea is quite simple. We will divide braced-init-list up into two=
=20
> > variation: list-braced-init-list and constr-braced-init-list. Most of=
=20
> the=20
> > text will remain the exact same, as they have almost identical behavior=
..=20
> >=20
> > The difference is that 13.3.1.7's list initialization overload=20
> resolution=20
> > rules will behave differently. list-braced-init-list initialization wil=
l=20
> > work exactly as it does. constr-braced-init-list will work opposite to=
=20
> the=20
> > current way. That is, it will check non-initializer_list constructors=
=20
> first,=20
> > then go to the initializer_list ones if no matching constructors are=20
> found.=20
> > All other uses will work identically; you can use these for aggregate=
=20
> > initialization and so forth just as before.=20
> >=20
> > The big issue is how constr-braced-init-lists are defined in the=20
> grammar. It=20
> > should look like this:=20
> >=20
> > {^ ... }=20
> >=20
> > The =93{=94 token followed by the =93^=94 token is what distinguishes t=
he=20
> > constr-braced-init-list from a list-braced-init-list.=20
>
> To make construction use more uniform syntax than the two we have, you=20
> want to add a third syntax to construct things? How does that make=20
> sense?=20
>
Because it's the only possible way of doing it without a breaking change?=
=20
Also, it's a minor variation of the syntax; it's hardly new. It's a slight=
=20
bending of the rules.
=20
>
> > ...=20
> > Currently, std::allocator_traits::construct is defined in terms of=20
> calling=20
> > new(/*stuff*/) T(std::forward<Args>(args)...). That will call=20
> constructors,=20
> > but it will only call constructors. If we have a simple struct that=20
> could=20
> > use aggregate initialization, we cannot use, for example, emplace on it=
:=20
>
> Arguably, it's also a bug that foo.emplace() can't append a=20
> vector<int> containing just {20}, but that isn't fixed by your=20
> proposal.
>
emplace isn't initializing; it's a function call. The call may happen to=20
forward its arguments to a constructor, but it's still a different=20
circumstance. Solving this requires a mechanism to forward a=20
braced-init-list elsewhere. And that's a whole different can of worms that=
=20
this proposal isn't trying to solve.
--=20
------=_Part_1764_16446875.1357350649543
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
<br><br>On Friday, January 4, 2013 4:04:10 PM UTC-8, Jeffrey Yasskin wrote:=
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bor=
der-left: 1px #ccc solid;padding-left: 1ex;">I haven't read the whole threa=
d. Sorry if some of this has been
<br>covered elsewhere.
<br>> By all rights, this code should always do the same thing: return a=
vector
<br>> containing 20 value-initialized elements. But it does not. MakeVec=
tor<int>()
<br>> will return a vector containing exactly one element.
<br>>
<br>> This is of much greater concern when dealing with more intricate t=
emplates.
<br>> Consider the following trivial template function:
<br>>
<br>> template<typename T>
<br>> T Process()
<br>> {
<br>> T t{};
<br>> //do stuff with t;
<br>> return T{t};
<br>> }
<br>>
<br>> This function creates a temporary, does some processing, and retur=
ns a copy
<br>> of it. This function requires that T be DefaultConstructible and
<br>> CopyConstructible, in addition to whatever =93do stuff with t=94 r=
equires.
<br>>
<br>> The problem is the last line. This line may violate the concept co=
nstraint.
<br>> Why? Because there is no guarantee that T does not have an initial=
izer_list
<br>> constructor that can match with a T. For an example of such a clas=
s,
<br>> consider std::vector<std::function<<wbr>void()>> as ou=
r T.
<br>
<br>Good point; I wouldn't have guessed that vector{same_type_vector}
<br>could (attempt to) construct a 1-element vector instead of copying the
<br>vector. That said, it can be fixed by using T(t) when intentionally
<br>calling a copy constructor.
<br></blockquote><div><br>That's uniform initialization not being uniform, =
then, which is exactly the problem this is trying to solve. If you can't us=
e {} everywhere, if you have to use () in some cases, then the syntax needs=
fixing.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;=
margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
Interestingly, libc++ uses SFINAE to exclude non-callable parameters
<br>from the std::function constructor, so this bug can't happen there.
<br>That may violate the standard, which uses Requires instead of "shall
<br>not participate in overload resolution".
<br>
<br>> The problem is that std::function has a non-explicit constructor t=
hat can
<br>> take any type that is CopyConstructible. And std::vector<std::f=
unction> is
<br>> CopyConstructible. Therefore, this will call the initializer_list
<br>> constructor. But the template function should not be calling the i=
nitializer
<br>> list constructor; it's not part of the allowed interface to T. The=
refore,
<br>> Process violates the concept constraint, through no fault on the u=
ser's
<br>> part.
<br>>
<br>> ...
<br>>
<br>> Design Overview
<br>>
<br>> The idea is quite simple. We will divide braced-init-list up into =
two
<br>> variation: list-braced-init-list and constr-braced-init-list. Most=
of the
<br>> text will remain the exact same, as they have almost identical beh=
avior.
<br>>
<br>> The difference is that 13.3.1.7's list initialization overload res=
olution
<br>> rules will behave differently. list-braced-init-list initializatio=
n will
<br>> work exactly as it does. constr-braced-init-list will work opposit=
e to the
<br>> current way. That is, it will check non-initializer_list construct=
ors first,
<br>> then go to the initializer_list ones if no matching constructors a=
re found.
<br>> All other uses will work identically; you can use these for aggreg=
ate
<br>> initialization and so forth just as before.
<br>>
<br>> The big issue is how constr-braced-init-lists are defined in the g=
rammar. It
<br>> should look like this:
<br>>
<br>> {^ ... }
<br>>
<br>> The =93{=94 token followed by the =93^=94 token is what distinguis=
hes the
<br>> constr-braced-init-list from a list-braced-init-list.
<br>
<br>To make construction use more uniform syntax than the two we have, you
<br>want to add a third syntax to construct things? How does that make
<br>sense?
<br></blockquote><div><br>Because it's the only possible way of doing it wi=
thout a breaking change? Also, it's a minor variation of the syntax; it's h=
ardly new. It's a slight bending of the rules.<br> </div><blockquote c=
lass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px=
#ccc solid;padding-left: 1ex;">
<br>> ...
<br>> Currently, std::allocator_traits::<wbr>construct is defined in ter=
ms of calling
<br>> new(/*stuff*/) T(std::forward<Args>(args)...)<wbr>. That wil=
l call constructors,
<br>> but it will only call constructors. If we have a simple struct tha=
t could
<br>> use aggregate initialization, we cannot use, for example, emplace =
on it:
<br>
<br>Arguably, it's also a bug that foo.emplace() can't append a
<br>vector<int> containing just {20}, but that isn't fixed by your
<br>proposal.<br></blockquote><div><br>emplace isn't initializing; it's a f=
unction call. The call may happen to forward its arguments to a constructor=
, but it's still a different circumstance. Solving this requires a mechanis=
m to forward a braced-init-list elsewhere. And that's a whole different can=
of worms that this proposal isn't trying to solve.<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1764_16446875.1357350649543--
.
Author: Jeffrey Yasskin <jyasskin@googlers.com>
Date: Sat, 5 Jan 2013 02:22:53 +0000
Raw View
On Sat, Jan 5, 2013 at 1:50 AM, Nicol Bolas <jmckesson@gmail.com> wrote:
> On Friday, January 4, 2013 4:04:10 PM UTC-8, Jeffrey Yasskin wrote:
>> Good point; I wouldn't have guessed that vector{same_type_vector}
>> could (attempt to) construct a 1-element vector instead of copying the
>> vector. That said, it can be fixed by using T(t) when intentionally
>> calling a copy constructor.
>
>
> That's uniform initialization not being uniform, then, which is exactly the
> problem this is trying to solve. If you can't use {} everywhere, if you have
> to use () in some cases, then the syntax needs fixing.
>
>> To make construction use more uniform syntax than the two we have, you
>> want to add a third syntax to construct things? How does that make
>> sense?
>
>
> Because it's the only possible way of doing it without a breaking change?
> Also, it's a minor variation of the syntax; it's hardly new. It's a slight
> bending of the rules.
To misquote you from above, "If you can't use {^} everywhere, if you
have to use {} in some cases, then the syntax needs fixing." Note that
I couldn't use {^20} to initialize a std::vector<int> holding just the
element "20", so you can't use {^} everywhere, so your proposal
doesn't solve the problem you set out to solve.
Jeffrey
--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Fri, 4 Jan 2013 18:59:38 -0800 (PST)
Raw View
------=_Part_1750_12836777.1357354778495
Content-Type: text/plain; charset=ISO-8859-1
On Friday, January 4, 2013 6:22:53 PM UTC-8, Jeffrey Yasskin wrote:
>
> On Sat, Jan 5, 2013 at 1:50 AM, Nicol Bolas <jmck...@gmail.com<javascript:>>
> wrote:
> > On Friday, January 4, 2013 4:04:10 PM UTC-8, Jeffrey Yasskin wrote:
> >> Good point; I wouldn't have guessed that vector{same_type_vector}
> >> could (attempt to) construct a 1-element vector instead of copying the
> >> vector. That said, it can be fixed by using T(t) when intentionally
> >> calling a copy constructor.
> >
> >
> > That's uniform initialization not being uniform, then, which is exactly
> the
> > problem this is trying to solve. If you can't use {} everywhere, if you
> have
> > to use () in some cases, then the syntax needs fixing.
> >
> >> To make construction use more uniform syntax than the two we have, you
> >> want to add a third syntax to construct things? How does that make
> >> sense?
> >
> >
> > Because it's the only possible way of doing it without a breaking
> change?
> > Also, it's a minor variation of the syntax; it's hardly new. It's a
> slight
> > bending of the rules.
>
> To misquote you from above, "If you can't use {^} everywhere, if you
> have to use {} in some cases, then the syntax needs fixing." Note that
> I couldn't use {^20} to initialize a std::vector<int> holding just the
> element "20", so you can't use {^} everywhere, so your proposal
> doesn't solve the problem you set out to solve.
>
Except that you can:
std::vector<int>{:{20}};
See?
--
------=_Part_1750_12836777.1357354778495
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Friday, January 4, 2013 6:22:53 PM UTC-8, Jeffrey Yasskin wrote:=
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bor=
der-left: 1px #ccc solid;padding-left: 1ex;">On Sat, Jan 5, 2013 at 1:50 AM=
, Nicol Bolas <<a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-=
mailto=3D"Kg03WYU0KEoJ">jmck...@gmail.com</a>> wrote:
<br>> On Friday, January 4, 2013 4:04:10 PM UTC-8, Jeffrey Yasskin wrote=
:
<br>>> Good point; I wouldn't have guessed that vector{same_type_vect=
or}
<br>>> could (attempt to) construct a 1-element vector instead of cop=
ying the
<br>>> vector. That said, it can be fixed by using T(t) when intentio=
nally
<br>>> calling a copy constructor.
<br>>
<br>>
<br>> That's uniform initialization not being uniform, then, which is ex=
actly the
<br>> problem this is trying to solve. If you can't use {} everywhere, i=
f you have
<br>> to use () in some cases, then the syntax needs fixing.
<br>>
<br>>> To make construction use more uniform syntax than the two we h=
ave, you
<br>>> want to add a third syntax to construct things? How does that =
make
<br>>> sense?
<br>>
<br>>
<br>> Because it's the only possible way of doing it without a breaking =
change?
<br>> Also, it's a minor variation of the syntax; it's hardly new. It's =
a slight
<br>> bending of the rules.
<br>
<br>To misquote you from above, "If you can't use {^} everywhere, if you
<br>have to use {} in some cases, then the syntax needs fixing." Note that
<br>I couldn't use {^20} to initialize a std::vector<int> holding jus=
t the
<br>element "20", so you can't use {^} everywhere, so your proposal
<br>doesn't solve the problem you set out to solve.<br></blockquote><div><b=
r>Except that you can:<br><br>std::vector<int>{:{20}};<br><br>See? <b=
r></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1750_12836777.1357354778495--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Fri, 4 Jan 2013 19:31:23 -0800 (PST)
Raw View
------=_Part_1705_8529349.1357356683528
Content-Type: text/plain; charset=ISO-8859-1
On Friday, January 4, 2013 6:59:38 PM UTC-8, Nicol Bolas wrote:
>
>
>
> On Friday, January 4, 2013 6:22:53 PM UTC-8, Jeffrey Yasskin wrote:
>>
>> On Sat, Jan 5, 2013 at 1:50 AM, Nicol Bolas <jmck...@gmail.com> wrote:
>> > On Friday, January 4, 2013 4:04:10 PM UTC-8, Jeffrey Yasskin wrote:
>> >> Good point; I wouldn't have guessed that vector{same_type_vector}
>> >> could (attempt to) construct a 1-element vector instead of copying the
>> >> vector. That said, it can be fixed by using T(t) when intentionally
>> >> calling a copy constructor.
>> >
>> >
>> > That's uniform initialization not being uniform, then, which is exactly
>> the
>> > problem this is trying to solve. If you can't use {} everywhere, if you
>> have
>> > to use () in some cases, then the syntax needs fixing.
>> >
>> >> To make construction use more uniform syntax than the two we have, you
>> >> want to add a third syntax to construct things? How does that make
>> >> sense?
>> >
>> >
>> > Because it's the only possible way of doing it without a breaking
>> change?
>> > Also, it's a minor variation of the syntax; it's hardly new. It's a
>> slight
>> > bending of the rules.
>>
>> To misquote you from above, "If you can't use {^} everywhere, if you
>> have to use {} in some cases, then the syntax needs fixing." Note that
>> I couldn't use {^20} to initialize a std::vector<int> holding just the
>> element "20", so you can't use {^} everywhere, so your proposal
>> doesn't solve the problem you set out to solve.
>>
>
> Except that you can:
>
> std::vector<int>{:{20}};
>
> See?
>
As I think about this, I came to realize that this isn't quite sufficient.
I realize that the idea should be this: one should be able to make
reasonable predictions about what a braced-init-list could call *without*knowing the type that it's initializing.
So if I'm in a template context, and I have some type T, and I want to
return a newly-constructed T using some parameters, I specifically want to
call a constructor. However, if T is an *aggregate*, it should still work;
I want to preserve aggregate initialization, while still calling a
constructor if T is not an aggregate.
There are really four different scenarios that you might come across with
uniform initialization with regard to mapping a braced-init-list to a
constructor. You might want:
- Initializer-list constructors only.
- Non-init-list constructors only.
- Initializer-list, then others (the current behavior).
- Non-init-list constructors, then init-list constructors.
Each of these are very reasonable things for the user to want, and we
should not force the user to have to live with one of these. So I propose
the following. We allow the user to choose which to use based on a "special
identifier" (ie: not a keyword).
{<special identifier>: ... }
The possible identifiers are:
- "l": Only look at initializer_list constructors.
- "c": Only look at non-initializer_list constructors.
- "lc": Look at initializer_list constructors first. Equivalent to {}.
- "cl": Look at non-initializer_list constructors first.
Therefore, if I want to create std::vector<int> with one value, I do this:
std::vector<int>{l: 20};
And if I have some type T that I want to construct with a variadic
parameter list, and I want T to be able to be an aggregate, but not to
allow the parameter list to use initializer_list constructors:
return {c: params...}; //Assuming we return a T by value.
I like this syntax very much. It's compact, clear, won't interfere with
anything else, and most important of all, gives the user the freedom to
choose how *all* ambiguities of construction are resolved.
--
------=_Part_1705_8529349.1357356683528
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Friday, January 4, 2013 6:59:38 PM UTC-8, Nicol Bolas wrote:<blo=
ckquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-=
left: 1px #ccc solid;padding-left: 1ex;"><br><br>On Friday, January 4, 2013=
6:22:53 PM UTC-8, Jeffrey Yasskin wrote:<blockquote class=3D"gmail_quote" =
style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left=
:1ex">On Sat, Jan 5, 2013 at 1:50 AM, Nicol Bolas <<a>jmck...@gmail.com<=
/a>> wrote:
<br>> On Friday, January 4, 2013 4:04:10 PM UTC-8, Jeffrey Yasskin wrote=
:
<br>>> Good point; I wouldn't have guessed that vector{same_type_vect=
or}
<br>>> could (attempt to) construct a 1-element vector instead of cop=
ying the
<br>>> vector. That said, it can be fixed by using T(t) when intentio=
nally
<br>>> calling a copy constructor.
<br>>
<br>>
<br>> That's uniform initialization not being uniform, then, which is ex=
actly the
<br>> problem this is trying to solve. If you can't use {} everywhere, i=
f you have
<br>> to use () in some cases, then the syntax needs fixing.
<br>>
<br>>> To make construction use more uniform syntax than the two we h=
ave, you
<br>>> want to add a third syntax to construct things? How does that =
make
<br>>> sense?
<br>>
<br>>
<br>> Because it's the only possible way of doing it without a breaking =
change?
<br>> Also, it's a minor variation of the syntax; it's hardly new. It's =
a slight
<br>> bending of the rules.
<br>
<br>To misquote you from above, "If you can't use {^} everywhere, if you
<br>have to use {} in some cases, then the syntax needs fixing." Note that
<br>I couldn't use {^20} to initialize a std::vector<int> holding jus=
t the
<br>element "20", so you can't use {^} everywhere, so your proposal
<br>doesn't solve the problem you set out to solve.<br></blockquote><div><b=
r>Except that you can:<br><br>std::vector<int>{:{20}};<br><br>See? <b=
r></div></blockquote><div><br>As I think about this, I came to realize that=
this isn't quite sufficient. I realize that the idea should be this: one s=
hould be able to make reasonable predictions about what a braced-init-list =
could call <i>without</i> knowing the type that it's initializing.<br><br>S=
o if I'm in a template context, and I have some type T, and I want to retur=
n a newly-constructed T using some parameters, I specifically want to call =
a constructor. However, if T is an <i>aggregate</i>, it should still work; =
I want to preserve aggregate initialization, while still calling a construc=
tor if T is not an aggregate.<br><br>There are really four different scenar=
ios that you might come across with uniform initialization with regard to m=
apping a braced-init-list to a constructor. You might want:<br><br><ul><li>=
Initializer-list constructors only.</li><li>Non-init-list constructors only=
..</li><li>Initializer-list, then others (the current behavior).<br></li><li=
>Non-init-list constructors, then init-list constructors.</li></ul>Each of =
these are very reasonable things for the user to want, and we should not fo=
rce the user to have to live with one of these. So I propose the following.=
We allow the user to choose which to use based on a "special identifier" (=
ie: not a keyword).<br><br><div class=3D"prettyprint" style=3D"background-c=
olor: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: s=
olid; border-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint=
"><div class=3D"subprettyprint"><span style=3D"color: #660;" class=3D"style=
d-by-prettify">{<</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">special identifier</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">>:</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">...</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">}</span></di=
v></code></div><br>The possible identifiers are:<br><ul><li>"l": Only look =
at initializer_list constructors.</li><li>"c": Only look at non-initializer=
_list constructors.</li><li>"lc": Look at initializer_list constructors fir=
st. Equivalent to {}.<br></li><li>"cl": Look at non-initializer_list constr=
uctors first.</li></ul><br>Therefore, if I want to create std::vector<in=
t> with one value, I do this:<br><br><div class=3D"prettyprint" style=3D=
"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); bo=
rder-style: solid; border-width: 1px; word-wrap: break-word;"><code class=
=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #000;"=
class=3D"styled-by-prettify">std</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">vector</span><span style=3D"color: #080;" class=3D"styled-b=
y-prettify"><int></span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy">l</span><span style=3D"color: #660;" class=3D"styled-by-prettify">:</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span =
style=3D"color: #066;" class=3D"styled-by-prettify">20</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">};</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"><br></span></div></code></div><br>And i=
f I have some type T that I want to construct with a variadic parameter lis=
t, and I want T to be able to be an aggregate, but not to allow the paramet=
er list to use initializer_list constructors:<br><br><div class=3D"prettypr=
int" style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, =
187, 187); border-style: solid; border-width: 1px; word-wrap: break-word;">=
<code class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"co=
lor: #008;" class=3D"styled-by-prettify">return</span><span style=3D"color:=
#000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify">c</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">:</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">params</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">...};</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an style=3D"color: #800;" class=3D"styled-by-prettify">//Assuming we return=
a T by value.</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br></span></div></code></div><br>I like this syntax very much. It's co=
mpact, clear, won't interfere with anything else, and most important of all=
, gives the user the freedom to choose how <i>all</i> ambiguities of constr=
uction are resolved.<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1705_8529349.1357356683528--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Fri, 4 Jan 2013 20:16:32 -0800 (PST)
Raw View
------=_Part_1757_22895013.1357359392362
Content-Type: multipart/alternative;
boundary="----=_Part_1758_27825581.1357359392362"
------=_Part_1758_27825581.1357359392362
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
OK, I've updated the proposal with the new {<special identifier>: } syntax.
Introduction
Braced-init-lists were originally used in object initialization with=20
aggregate initialization. In the development of C++11, the idea was=20
extended to include non-aggregate types through the use of a special=20
initializer_list type.
This idea was ultimately extended into what became known as uniform=20
initialization: one could initialize any type via the use of a=20
braced-init-list. Doing so provides a number of advantages, among them is=
=20
uniform initialization behavior and the elimination of the most vexing=20
parse. In a perfect world, we would always use uniform initialization and=
=20
never use direct constructor syntax.
However, despite being called =93uniform initialization,=94 it cannot be=20
uniformly used everywhere, due to a critical flaw that prevents its use=20
towards these ends. This proposal intends to correct this flaw, thus=20
allowing it to be used in all possible cases of object construction, while=
=20
having well-defined results.
Motivation and Scope
The flaw in uniform initialization is quite simple to see in the standard=
=20
library. The std::vector type has an explicit constructor which takes a=20
single std::vector::size_type, which is an integral type. std::vector also=
=20
has a constructor that takes an initializer_list<T>.
For most types, these constructors can coexist with uniform initialization=
=20
quite reasonably. For example:
std::vector<A> v1{20};
std::vector<A> v2{A{}};
std::vector<A> v3{A{}, A{}, A{}};
In this example, v1 is an array of 20 value-constructed values. v2 is an=20
array of 1 value-constructed element. v3 is an array of 3 value-constructed=
=20
elements.
This is all well and good, until we do this:
std::vector<int> v1{20};
std::vector<int> v2{int{}};
std::vector<int> v3{int{}, int{}, int{}};
v2 and v3 retain their old meaning. But v1 is now very different. It is an=
=20
array containing a single element, the number 20. Why?
Because uniform initialization syntax always prefers initializer list=20
constructors if one is available that would fit the braced-init-list. This=
=20
is a consequence of uniform initialization syntax using the same syntax as=
=20
initializer lists: the braced-init-list. And since=20
std::vector<int>::vector(std::initializer_list<int>) matches the=20
braced-init-list ({20}), it will be preferred over=20
std::vector<int>::vector(std::vector<int>::size_type)
This is a problem because there is *no way* to get at the size_typeconstruc=
tor via uniform initialization. There is no syntax that we can=20
employ which will cause the conflicting initializer_list constructor to be=
=20
ignored or to do anything else that would allow us to get at a different=20
set of constructors.
Now, this may seem like a rather unimportant issue. After all, if I know=20
that I have to use constructor initialization with vector<int>, then I can=
=20
simply do that. But consider code that is generic on the vector's type:
template<typename T>
std::vector<T> MakeVector()
{
return std::vector<T>{20};
}
By all rights, this code should always do the same thing: return a vectorco=
ntaining 20 value-initialized elements. But it does not.=20
MakeVector<int>() will return a vector containing exactly one element.
This is of much greater concern when dealing with more intricate templates.=
=20
Consider the following trivial template function:
template<typename T>
T Process()
{
T t{};
//do stuff with t;
return T{t};
}
This function creates a temporary, does some processing, and returns a copy=
=20
of it. This function requires that T be DefaultConstructible and=20
CopyConstructible, in addition to whatever =93do stuff with t=94 requires.
The problem is the last line. This line *may* violate the concept=20
constraint. Why? Because there is no guarantee that T does *not* have an=20
initializer_list constructor that can match with a T. For an example of=20
such a class, consider std::vector<std::function<void()>> as our T.
The problem is that std::function has a non-explicit constructor that can=
=20
take *any* type that is CopyConstructible. And std::vector<std::function>is=
CopyConstructible. Therefore, this will call the initializer_list=20
constructor. But the template function should not be calling the=20
initializer list constructor; it's not part of the allowed interface to T.=
=20
Therefore, Process violates the concept constraint, through no fault on the=
=20
user's part.
What this means is that you cannot use uniform initialization in generic=20
code where the exact type of the object being constructed is derived from a=
=20
template parameter. This is because there is no way for the user to=20
explicitly choose which constructors to call.
Design Overview
The idea is a bit complex, but not unreasonably so. We recognize that there=
=20
are 4 possible ways that a user could want to use uniform initialization:
1.=20
=20
Call a non-initializer_list constructor.
2.=20
=20
Call an initializer_list constructor.
3.=20
=20
Call a non-initializer_list constructor where applicable; if none fit,=
=20
call an initializer_list constructor.
4.=20
=20
Call an initializer_list constructor where applicable; if none fit, call=
=20
a non-initializer_list constructor.
=20
These variation *only* affect which constructors are considered during=20
overload resolution; in every other respect, they work like a regular=20
braced-init-list. So if they're initializing an aggregate, *all of them*wil=
l work as normal via aggregate initialization rules. The only thing that=20
changes, outside of the grammar that will be discussed presently, is=20
section 13.3.1.7's list initialization overload resolution rules. They will=
=20
cover the four cases.
This means that there must be four separate types of braced-init-lists.=20
They will all behave the same except for how they interact with 13.3.1.7.
The big issue is how these special braced-init-lists are defined in the=20
grammar. It should look like this:
{<special identifier>: ... }
The =93<special identifer>=94 is like the =93override=94 and =93final=94 sp=
ecial=20
identifiers in classes. There will be four, each corresponding to a=20
different scheme:
1.=20
=20
=93c=94: Call a non-initializer_list constructor.
2.=20
=20
=93l=94: Call an initializer_list constructor.
3.=20
=20
=93cl=94: Call a non-initializer_list constructor where applicable; if n=
one=20
fit, call an initializer_list constructor.
Note
=20
I am not entirely convinced that we need this one. I personally really=
=20
like the idea of forcing you to choose which set of constructors a=20
braced-init-list should call. But since we can't get rid of the old synt=
ax,=20
orthogonality requires that we also allow the opposite convention to wor=
k.
4.=20
=20
=93lc=94: Call an initializer_list constructor where applicable; if none=
=20
fit, call a non-initializer_list constructor. Equivalent to =93{}=94
=20
Impact on the Standard
Depending on how we want to handle the wording, we may need a new set of =
=93
list-initialization=94 types. 13.3.1.7 never mentions braced-init-list; it=
=20
only operates in terms of list-initialization, which stems from a specific=
=20
use of braced-init-list. We could have it say something like =93if the=20
braced-init-list that issues this constructor is one of these types, then=
=20
....=94 Or we could provide different forms of =93list-initialization.=94
It should cause zero backwards compatibility problems. Regular=20
braced-init-lists should have the same behavior as before, and the new=20
grammar would not have been legal before. Also, see the Design Decisions=20
section.
Design Decisions
What follows are some alternatives and discarded designs, and the reasons=
=20
for not choosing them.
Library vs Language
Originally, I considered a library-based solution to the issue. This would=
=20
have required adding a special opaque type taken as a parameter to various=
=20
calls. Since the opaque type is different from other types, it would=20
prevent the braced-init-list from binding to an initializer_listconstructor=
, thus disambiguating the call.
This is problematic for two reasons. First, it adds some complexity to=20
various container classes, as they have to prevent the user from using the=
=20
opaque type as the member or allocator types. But the primary reason that=
=20
this is not a good solution is because it only solves the problem for the=
=20
standard library.
We should not ask every user who writes an initializer_list constructor to=
=20
go though and add a suffix parameter to various functions that could=20
interfere. This is a problem introduced by the language, and it is best=20
solved in the language.
Binary Choice
The original design was essentially a binary choice: you pick constructors=
=20
first or initializer_list first.=20
This was revealed to be a bad idea, because sometimes you want something to=
=20
only consider non-init constructors or only consider initializer_list=20
constructors. The enumeration of the four possibilities is important,=20
especially for template code.
The reason why we need =93c=94 when we could just use regular constructor=
=20
syntax is to allow the initialization of aggregates. For example, consider=
=20
this aggregate:
struct Agg
{
int x;
float y;
};
We can initialize this via aggregate initialization:
Agg agg{5, 32.3f};
Thanks to std::vector's initializer_list constructor, we can even=20
initialize arrays of them:
std::vector<Agg> aggs{{-403, 234.0f}, {22, -19.89f}, {0, 4.2f}};
And we can push them back into a vector:
aggs.push_back({3, 92.4f});
What we *can't* do is *emplace* them back:
aggs.emplace_back(3, 92.4f); //Not allowed.
We can only initialize an aggregate in a standard library class by copy,=20
not directly. Why not? Because allocator_traits<A>::construct explicitly=20
calls the constructor (if A::construct doesn't exist). And Agg doesn't have=
=20
a constructor.
With the proposed feature, we can easily redefine=20
allocator_traits<A>::construct in terms of {c: params...}. This will call=
=20
constructors *or* employ aggregate initialization on the argument.
That wouldn't be possible without the =93c=94 syntax. We (probably) don't w=
ant=20
to allow initializer_list initialization through=20
allocator_traits<A>::construct, but we should allow aggregate=20
initialization via it.
Change the Original
There was an alternate design to resolve the issue. Simply declare that non=
-
initializer_list constructors have priority, instead of the other way=20
around. This would make these completely unambiguous:
std::vector<int> v1{20};
std::vector<int> v2{{20}};
v1 is using the size_type constructor. v2 is clearly calling a=20
single-argument constructor using a braced-init-list.
The obvious problem with this is that it is a breaking change and a *silent=
*one at that.
Even worse, it doesn't look uniform:
std::array<int, 6> a1 =3D {1, 2, 3, 4, 5, 6}; //Brace elision removes the e=
xtra pair.
std::vector<int> v1 =3D {1, 2, 3, 4, 5, 6}; //Brace "elision" possible.
std::array<int, 1> a2 =3D {1}; //Brace elision still works.
std::vector<int> v2 =3D {1}; //Brace "elision" no longer possible due to =
conflict. Does the wrong thing.
Honestly, this would be the preferable solution, if it were not a breaking=
=20
change. But it is, so we probably shouldn't do it.
There is a way to use this to make a *noisy* breaking change. If we=20
effectively make {} equivalent to {=93l=94}, disallowing non-initializer_li=
st=20
constructors, then the compiler will at least complain about the problem.=
=20
This would force the user to go through and annotate their expectations=20
directly. And we have more uniformity: {} means initialize-from-list, while=
=20
{:} means possibly call constructors.
Possible Addendum
Presently, explicit constructors cannot be called in=20
copy-list-initialization contexts. This can force the use of a long,=20
complex type in places where it is not needed. For example:
LongComplexFunctionReturnType<ThatIShouldn,tTypeAgain> FuncName(...)
{
//Compute stuff.
return LongComplexFunctionReturnType<ThatIShouldn,tTypeAgain>{params};
}
The proposed syntax of providing parameters to the braced-init-list means=
=20
that we could have additional parameters that allow a braced-init-list to=
=20
call explicit constructors even in copy-list-initialization contexts:
LongComplexFunctionReturnType<ThatIShouldn,tTypeAgain> FuncName(...)
{
//Compute stuff.
return {explicit c: params};
}
The main reason for introducing the copy-list-initialization to begin with=
=20
was due to concerns that not having it effectively made explicit pointless,=
=20
since people could easily end-run around it. This allows us to not have to=
=20
repeat the type, but we do have to at least state in our code the intent to=
=20
call explicit constructors.
Technical Specifications
Acknowledgements
-=20
=20
Malte Skarupke: For bringing up the issue of using uniform=20
initialization in generic code.
-=20
=20
Jo=EBl Lamotte: For coming up with the idea to use =93{:}=94 syntax.
-=20
=20
Jeffrey Yasskin and Nikolay Ivchenkov, who offered valuable criticism of=
=20
the idea that led to the current identifier syntax.
=20
References
--=20
------=_Part_1758_27825581.1357359392362
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
OK, I've updated the proposal with the new {<special identifier>: } s=
yntax.<br><br><div class=3D"section" title=3D"Introduction"><div class=3D"t=
itlepage"><div><div><h2 class=3D"title" style=3D"clear: both"><a name=3D"d0=
e6"></a>Introduction</h2></div></div></div><p>Braced-init-lists were origin=
ally used in object initialization with aggregate
initialization. In the development of C++11, the idea was exten=
ded to include
non-aggregate types through the use of a special <span class=3D=
"type">initializer_list</span>
type.</p><p>This idea was ultimately extended into what became =
known as uniform initialization:
one could initialize any type via the use of a braced-init-list=
.. Doing so provides a
number of advantages, among them is uniform initialization beha=
vior and the elimination
of the most vexing parse. In a perfect world, we would always u=
se uniform initialization
and never use direct constructor syntax.</p><p>However, despite=
being called <span class=3D"quote">=93<span class=3D"quote">uniform initia=
lization,</span>=94</span> it cannot be
uniformly used everywhere, due to a critical flaw that prevents=
its use towards these
ends. This proposal intends to correct this flaw, thus allowing=
it to be used in all
possible cases of object construction, while having well-define=
d results.</p></div><div class=3D"section" title=3D"Motivation and Scope"><=
div class=3D"titlepage"><div><div><h2 class=3D"title" style=3D"clear: both"=
><a name=3D"d0e21"></a>Motivation and Scope</h2></div></div></div><p>The fl=
aw in uniform initialization is quite simple to see in the standard library=
.. The
<span class=3D"type">std::vector</span> type has an explici=
t constructor which takes a single
<span class=3D"type">std::vector::size_type</span>, which i=
s an integral type.
<span class=3D"type">std::vector</span> also has a construc=
tor that takes an
<span class=3D"type">initializer_list<T></span>.</p><=
p>For most types, these constructors can coexist with uniform initializatio=
n quite
reasonably. For example:</p><pre class=3D"programlisting">std::=
vector<A> v1{20};
std::vector<A> v2{A{}};
std::vector<A> v3{A{}, A{}, A{}};</pre><p>In this example, <code clas=
s=3D"varname">v1</code> is an array of 20 value-constructed values.
<code class=3D"varname">v2</code> is an array of 1 value-co=
nstructed element.
<code class=3D"varname">v3</code> is an array of 3 value-co=
nstructed elements.</p><p>This is all well and good, until we do this:</p><=
pre class=3D"programlisting">std::vector<int> v1{20};
std::vector<int> v2{int{}};
std::vector<int> v3{int{}, int{}, int{}};</pre><p><code class=3D"varn=
ame">v2</code> and <code class=3D"varname">v3</code> retain their old meani=
ng. But
<code class=3D"varname">v1</code> is now very different. It=
is an array containing a single
element, the number 20. Why?</p><p>Because uniform initializati=
on syntax always prefers initializer list constructors if
one is available that would fit the braced-init-list. This is a=
consequence of uniform
initialization syntax using the same syntax as initializer list=
s: the braced-init-list.
And since
<code class=3D"function">std::vector<int>::vector(std=
::initializer_list<int>)</code>
matches the braced-init-list (<code class=3D"literal">{20}</cod=
e>), it will be preferred over
<code class=3D"function">std::vector<int>::vector(std=
::vector<int>::size_type)</code></p><p>This is a problem because ther=
e is <span class=3D"emphasis"><em>no way</em></span> to get at the
<span class=3D"type">size_type</span> constructor via unifo=
rm initialization. There is no syntax
that we can employ which will cause the conflicting <span class=
=3D"type">initializer_list</span>
constructor to be ignored or to do anything else that would all=
ow us to get at a
different set of constructors.</p><p>Now, this may seem like a =
rather unimportant issue. After all, if I know that I have
to use constructor initialization with <span class=3D"type">vec=
tor<int></span>, then I can simply do
that. But consider code that is generic on the <span class=3D"t=
ype">vector</span>'s type:</p><pre class=3D"programlisting">template<typ=
ename T>
std::vector<T> MakeVector()
{
return std::vector<T>{20};
}</pre><p>By all rights, this code should always do the same thing: return =
a <span class=3D"type">vector</span>
containing 20 value-initialized elements. But it does not.
<code class=3D"function">MakeVector<int>()</code> wil=
l return a <span class=3D"type">vector</span>
containing exactly one element.</p><p>This is of much greater c=
oncern when dealing with more intricate templates. Consider
the following trivial template function:</p><pre class=3D"progr=
amlisting">template<typename T>
T Process()
{
T t{};
//do stuff with t;
return T{t};
}</pre><p>This function creates a temporary, does some processing, and retu=
rns a copy of it.
This function requires that <span class=3D"type">T</span> be De=
faultConstructible and
CopyConstructible, in addition to whatever <span class=3D"quote=
">=93<span class=3D"quote">do stuff with t</span>=94</span>
requires.</p><p>The problem is the last line. This line <span c=
lass=3D"emphasis"><em>may</em></span> violate the concept
constraint. Why? Because there is no guarantee that <span class=
=3D"type">T</span> does
<span class=3D"emphasis"><em>not</em></span> have an <span =
class=3D"type">initializer_list</span> constructor that can
match with a <span class=3D"type">T</span>. For an example of s=
uch a class, consider
<span class=3D"type">std::vector<std::function<void()=
>></span> as our <span class=3D"type">T</span>.</p><p>The problem is =
that <span class=3D"type">std::function</span> has a non-explicit construct=
or that can
take <span class=3D"emphasis"><em>any</em></span> type that is =
CopyConstructible. And
<span class=3D"type">std::vector<std::function></span=
> is CopyConstructible. Therefore, this
will call the initializer_list constructor. But the template fu=
nction should not be
calling the initializer list constructor; it's not part of the =
allowed interface to T.
Therefore, <code class=3D"function">Process</code> violates the=
concept constraint, through no
fault on the user's part.</p><p>What this means is that you can=
not use uniform initialization in generic code where
the exact type of the object being constructed is derived from =
a template parameter.
This is because there is no way for the user to explicitly choo=
se which constructors to
call.</p></div><div class=3D"section" title=3D"Design Overview"=
><div class=3D"titlepage"><div><div><h2 class=3D"title" style=3D"clear: bot=
h"><a name=3D"d0e160"></a>Design Overview</h2></div></div></div><p>The idea=
is a bit complex, but not unreasonably so. We recognize that there are 4
possible ways that a user could want to use uniform initializat=
ion:</p><div class=3D"orderedlist"><ol class=3D"orderedlist" type=3D"1"><li=
class=3D"listitem"><p>Call a non-initializer_list constructor.</p></li><li=
class=3D"listitem"><p>Call an initializer_list constructor.</p></li><li cl=
ass=3D"listitem"><p>Call a non-initializer_list constructor where applicabl=
e; if none fit, call an
initializer_list constructor.</p></li><li class=3D"list=
item"><p>Call an initializer_list constructor where applicable; if none fit=
, call a
non-initializer_list constructor.</p></li></ol></div><p=
>These variation <span class=3D"emphasis"><em>only</em></span> affect which=
constructors are considered
during overload resolution; in every other respect, they work l=
ike a regular
braced-init-list. So if they're initializing an aggregate, <spa=
n class=3D"emphasis"><em>all of
them</em></span> will work as normal via aggregate initiali=
zation rules. The only
thing that changes, outside of the grammar that will be discuss=
ed presently, is section
13.3.1.7's list initialization overload resolution rules. They =
will cover the four
cases.</p><p>This means that there must be four separate types =
of braced-init-lists. They will all
behave the same except for how they interact with 13.3.1.7.</p>=
<p>The big issue is how these special braced-init-lists are defined in the =
grammar. It
should look like this:</p><pre class=3D"programlisting">{<sp=
ecial identifier>: ... }</pre><p>The <span class=3D"quote">=93<span clas=
s=3D"quote"><code class=3D"literal"><special identifer></code></span>=
=94</span> is like the
<span class=3D"quote">=93<span class=3D"quote">override</sp=
an>=94</span> and <span class=3D"quote">=93<span class=3D"quote">final</spa=
n>=94</span> special identifiers in classes.
There will be four, each corresponding to a different scheme:</=
p><div class=3D"orderedlist"><ol class=3D"orderedlist" type=3D"1"><li class=
=3D"listitem"><p><span class=3D"quote">=93<span class=3D"quote"><code class=
=3D"literal">c</code></span>=94</span>: Call a non-initializer_list
constructor.</p></li><li class=3D"listitem"><p><span cl=
ass=3D"quote">=93<span class=3D"quote"><code class=3D"literal">l</code></sp=
an>=94</span>: Call an initializer_list
constructor.</p></li><li class=3D"listitem"><p><span cl=
ass=3D"quote">=93<span class=3D"quote"><code class=3D"literal">cl</code></s=
pan>=94</span>: Call a non-initializer_list constructor
where applicable; if none fit, call an initializer_list=
constructor.</p><div class=3D"note" title=3D"Note" style=3D"margin-left: 0=
..5in; margin-right: 0.5in;"><h3 class=3D"title">Note</h3><p>I am not entire=
ly convinced that we need this one. I personally really
like the idea of forcing you to choose which set of=
constructors a
braced-init-list should call. But since we can't ge=
t rid of the old syntax,
orthogonality requires that we also allow the oppos=
ite convention to
work.</p></div></li><li class=3D"listitem"><p><span=
class=3D"quote">=93<span class=3D"quote"><code class=3D"literal">lc</code>=
</span>=94</span>: Call an initializer_list constructor
where applicable; if none fit, call a non-initializer_l=
ist constructor.
Equivalent to <span class=3D"quote">=93<span class=3D"q=
uote"><code class=3D"literal">{}</code></span>=94</span></p></li></ol></div=
></div><div class=3D"section" title=3D"Impact on the Standard"><div class=
=3D"titlepage"><div><div><h2 class=3D"title" style=3D"clear: both"><a name=
=3D"d0e235"></a>Impact on the Standard</h2></div></div></div><p>Depending o=
n how we want to handle the wording, we may need a new set of
<span class=3D"quote">=93<span class=3D"quote">list-initial=
ization</span>=94</span> types. 13.3.1.7 never mentions braced-init-list;
it only operates in terms of list-initialization, which stems f=
rom a specific use of
braced-init-list. We could have it say something like <span cla=
ss=3D"quote">=93<span class=3D"quote">if the braced-init-list
that issues this constructor is one of these types, then ..=
..</span>=94</span> Or we could
provide different forms of <span class=3D"quote">=93<span class=
=3D"quote">list-initialization.</span>=94</span></p><p>It should cause zero=
backwards compatibility problems. Regular braced-init-lists
should have the same behavior as before, and the new grammar wo=
uld not have been legal
before. Also, see the Design Decisions section.</p></div><div c=
lass=3D"section" title=3D"Design Decisions"><div class=3D"titlepage"><div><=
div><h2 class=3D"title" style=3D"clear: both"><a name=3D"d0e250"></a>Design=
Decisions</h2></div></div></div><p>What follows are some alternatives and =
discarded designs, and the reasons for not
choosing them.</p><div class=3D"section" title=3D"Library vs La=
nguage"><div class=3D"titlepage"><div><div><h3 class=3D"title"><a name=3D"d=
0e255"></a>Library vs Language</h3></div></div></div><p>Originally, I consi=
dered a library-based solution to the issue. This would have
required adding a special opaque type taken as a parameter =
to various calls. Since
the opaque type is different from other types, it would pre=
vent the braced-init-list
from binding to an <span class=3D"type">initializer_list</s=
pan> constructor, thus disambiguating
the call.</p><p>This is problematic for two reasons. First,=
it adds some complexity to various
container classes, as they have to prevent the user from us=
ing the opaque type as
the member or allocator types. But the primary reason that =
this is not a good
solution is because it only solves the problem for the stan=
dard library.</p><p>We should not ask every user who writes an <span class=
=3D"type">initializer_list</span>
constructor to go though and add a suffix parameter to vari=
ous functions that could
interfere. This is a problem introduced by the language, an=
d it is best solved in
the language.</p></div><div class=3D"section" title=3D"Bina=
ry Choice"><div class=3D"titlepage"><div><div><h3 class=3D"title"><a name=
=3D"d0e270"></a>Binary Choice</h3></div></div></div><p>The original design =
was essentially a binary choice: you pick constructors
first or initializer_list first. </p><p>This was reveal=
ed to be a bad idea, because sometimes you want something to
only consider non-init constructors or only consider in=
itializer_list
constructors. The enumeration of the four possibilities=
is important, especially
for template code.</p><p>The reason why we need <span c=
lass=3D"quote">=93<span class=3D"quote"><code class=3D"literal">c</code></s=
pan>=94</span> when we could just
use regular constructor syntax is to allow the initiali=
zation of aggregates. For
example, consider this aggregate:</p><pre class=3D"prog=
ramlisting">struct Agg
{
int x;
float y;
};</pre><p>We can initialize this via aggregate initialization:</p><pre cla=
ss=3D"programlisting">Agg agg{5, 32.3f};</pre><p>Thanks to <span class=3D"t=
ype">std::vector</span>'s <span class=3D"type">initializer_list</span>
constructor, we can even initialize arrays of them:</p>=
<pre class=3D"programlisting">std::vector<Agg> aggs{{-403, 234.0f}, {=
22, -19.89f}, {0, 4.2f}};</pre><p>And we can push them back into a vector:<=
/p><pre class=3D"programlisting">aggs.push_back({3, 92.4f});</pre><p>What w=
e <span class=3D"emphasis"><em>can't</em></span> do is <span class=3D"empha=
sis"><em>emplace</em></span> them
back:</p><pre class=3D"programlisting">aggs.emplace_bac=
k(3, 92.4f); //Not allowed.</pre><p>We can only initialize an aggregate in =
a standard library class by copy, not
directly. Why not? Because <span class=3D"type">allocat=
or_traits<A>::construct</span>
explicitly calls the constructor (if <span class=3D"typ=
e">A::construct</span> doesn't exist).
And <span class=3D"type">Agg</span> doesn't have a cons=
tructor.</p><p>With the proposed feature, we can easily redefine
<span class=3D"type">allocator_traits<A>::con=
struct</span> in terms of <code class=3D"literal">{c:
params...}</code>. This will call constructors <spa=
n class=3D"emphasis"><em>or</em></span>
employ aggregate initialization on the argument.</p><p>=
That wouldn't be possible without the <span class=3D"quote">=93<span class=
=3D"quote">c</span>=94</span> syntax. We (probably)
don't want to allow <span class=3D"type">initializer_list</=
span> initialization through
<span class=3D"type">allocator_traits<A>::constru=
ct</span>, but we should allow aggregate
initialization via it.</p></div><div class=3D"section" titl=
e=3D"Change the Original"><div class=3D"titlepage"><div><div><h3 class=3D"t=
itle"><a name=3D"d0e346"></a>Change the Original</h3></div></div></div><p>T=
here was an alternate design to resolve the issue. Simply declare that
non-<span class=3D"type">initializer_list</span> constr=
uctors have priority, instead of the
other way around. This would make these completely unambigu=
ous:</p><pre class=3D"programlisting">std::vector<int> v1{20};
std::vector<int> v2{{20}};</pre><p><span class=3D"type">v1</span> is =
using the <span class=3D"type">size_type</span> constructor. <span class=3D=
"type">v2</span>
is clearly calling a single-argument constructor using a br=
aced-init-list.</p><p>The obvious problem with this is that it is a breakin=
g change and a
<span class=3D"emphasis"><em>silent</em></span> one at =
that.</p><p>Even worse, it doesn't look uniform:</p><pre class=3D"programli=
sting">std::array<int, 6> a1 =3D {1, 2, 3, 4, 5, 6}; //Brace elision =
removes the extra pair.
std::vector<int> v1 =3D {1, 2, 3, 4, 5, 6}; //Brace "elision" possibl=
e.
std::array<int, 1> a2 =3D {1}; //Brace elision still works.
std::vector<int> v2 =3D {1}; //Brace "elision" no longer possible d=
ue to conflict. Does the wrong thing.</pre><p>Honestly, this would be the p=
referable solution, if it were not a breaking change.
But it is, so we probably shouldn't do it.</p><p>There is a=
way to use this to make a <span class=3D"emphasis"><em>noisy</em></span> b=
reaking change.
If we effectively make {} equivalent to {<span class=3D"quo=
te">=93<span class=3D"quote">l</span>=94</span>}, disallowing
non-initializer_list constructors, then the compiler will a=
t least complain about
the problem. This would force the user to go through and an=
notate their expectations
directly. And we have more uniformity: {} means initialize-=
from-list, while {:}
means possibly call constructors.</p></div><div class=3D"se=
ction" title=3D"Possible Addendum"><div class=3D"titlepage"><div><div><h3 c=
lass=3D"title"><a name=3D"d0e385"></a>Possible Addendum</h3></div></div></d=
iv><p>Presently, explicit constructors cannot be called in copy-list-initia=
lization
contexts. This can force the use of a long, complex type in=
places where it is not
needed. For example:</p><pre class=3D"programlisting">LongC=
omplexFunctionReturnType<ThatIShouldn,tTypeAgain> FuncName(...)
{
//Compute stuff.
return LongComplexFunctionReturnType<ThatIShouldn,tTypeAgain>{para=
ms};
}</pre><p>The proposed syntax of providing parameters to the braced-init-li=
st means that we
could have additional parameters that allow a braced-init-l=
ist to call explicit
constructors even in copy-list-initialization contexts:</p>=
<pre class=3D"programlisting">LongComplexFunctionReturnType<ThatIShouldn=
,tTypeAgain> FuncName(...)
{
//Compute stuff.
return {explicit c: params};
}</pre><p>The main reason for introducing the copy-list-initialization to b=
egin with was due
to concerns that not having it effectively made <code class=
=3D"literal">explicit</code>
pointless, since people could easily end-run around it. Thi=
s allows us to not have
to repeat the type, but we do have to at least state in our=
code the intent to call
<code class=3D"literal">explicit</code> constructors.</=
p></div></div><div class=3D"section" title=3D"Technical Specifications"><di=
v class=3D"titlepage"><div><div><h2 class=3D"title" style=3D"clear: both"><=
a name=3D"d0e404"></a>Technical Specifications</h2></div></div></div></div>=
<div class=3D"section" title=3D"Acknowledgements"><div class=3D"titlepage">=
<div><div><h2 class=3D"title" style=3D"clear: both"><a name=3D"d0e408"></a>=
Acknowledgements</h2></div></div></div><div class=3D"itemizedlist"><ul clas=
s=3D"itemizedlist" type=3D"disc"><li class=3D"listitem"><p>Malte Skarupke: =
For bringing up the issue of using uniform initialization in
generic code.</p></li><li class=3D"listitem"><p>Jo=EBl =
Lamotte: For coming up with the idea to use <span class=3D"quote">=93<span =
class=3D"quote">{:}</span>=94</span>
syntax.</p></li><li class=3D"listitem"><p>Jeffrey Yassk=
in and Nikolay Ivchenkov, who offered valuable criticism of the
idea that led to the current identifier syntax.</p></li=
></ul></div></div><div class=3D"titlepage"><div><div><h2 class=3D"title" st=
yle=3D"clear: both"><a name=3D"d0e424"></a>References</h2></div></div></div=
><br>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1758_27825581.1357359392362--
------=_Part_1757_22895013.1357359392362
Content-Type: text/html; charset=US-ASCII;
name="Towards More Uniform Initialization.html"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="Towards More Uniform Initialization.html"
X-Attachment-Id: 85dbb6f1-493e-4a93-bb02-1695ec252de1
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Towards More Uniform Initialization</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="article" title="Towards More Uniform Initialization"><div class="titlepage"><div><div><h2 class="title"><a name="d0e3"></a>Towards More Uniform Initialization</h2></div></div><hr></div><div class="section" title="Introduction"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e6"></a>Introduction</h2></div></div></div><p>Braced-init-lists were originally used in object initialization with aggregate
initialization. In the development of C++11, the idea was extended to include
non-aggregate types through the use of a special <span class="type">initializer_list</span>
type.</p><p>This idea was ultimately extended into what became known as uniform initialization:
one could initialize any type via the use of a braced-init-list. Doing so provides a
number of advantages, among them is uniform initialization behavior and the elimination
of the most vexing parse. In a perfect world, we would always use uniform initialization
and never use direct constructor syntax.</p><p>However, despite being called <span class="quote">“<span class="quote">uniform initialization,</span>”</span> it cannot be
uniformly used everywhere, due to a critical flaw that prevents its use towards these
ends. This proposal intends to correct this flaw, thus allowing it to be used in all
possible cases of object construction, while having well-defined results.</p></div><div class="section" title="Motivation and Scope"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e21"></a>Motivation and Scope</h2></div></div></div><p>The flaw in uniform initialization is quite simple to see in the standard library. The
<span class="type">std::vector</span> type has an explicit constructor which takes a single
<span class="type">std::vector::size_type</span>, which is an integral type.
<span class="type">std::vector</span> also has a constructor that takes an
<span class="type">initializer_list<T></span>.</p><p>For most types, these constructors can coexist with uniform initialization quite
reasonably. For example:</p><pre class="programlisting">std::vector<A> v1{20};
std::vector<A> v2{A{}};
std::vector<A> v3{A{}, A{}, A{}};</pre><p>In this example, <code class="varname">v1</code> is an array of 20 value-constructed values.
<code class="varname">v2</code> is an array of 1 value-constructed element.
<code class="varname">v3</code> is an array of 3 value-constructed elements.</p><p>This is all well and good, until we do this:</p><pre class="programlisting">std::vector<int> v1{20};
std::vector<int> v2{int{}};
std::vector<int> v3{int{}, int{}, int{}};</pre><p><code class="varname">v2</code> and <code class="varname">v3</code> retain their old meaning. But
<code class="varname">v1</code> is now very different. It is an array containing a single
element, the number 20. Why?</p><p>Because uniform initialization syntax always prefers initializer list constructors if
one is available that would fit the braced-init-list. This is a consequence of uniform
initialization syntax using the same syntax as initializer lists: the braced-init-list.
And since
<code class="function">std::vector<int>::vector(std::initializer_list<int>)</code>
matches the braced-init-list (<code class="literal">{20}</code>), it will be preferred over
<code class="function">std::vector<int>::vector(std::vector<int>::size_type)</code></p><p>This is a problem because there is <span class="emphasis"><em>no way</em></span> to get at the
<span class="type">size_type</span> constructor via uniform initialization. There is no syntax
that we can employ which will cause the conflicting <span class="type">initializer_list</span>
constructor to be ignored or to do anything else that would allow us to get at a
different set of constructors.</p><p>Now, this may seem like a rather unimportant issue. After all, if I know that I have
to use constructor initialization with <span class="type">vector<int></span>, then I can simply do
that. But consider code that is generic on the <span class="type">vector</span>'s type:</p><pre class="programlisting">template<typename T>
std::vector<T> MakeVector()
{
return std::vector<T>{20};
}</pre><p>By all rights, this code should always do the same thing: return a <span class="type">vector</span>
containing 20 value-initialized elements. But it does not.
<code class="function">MakeVector<int>()</code> will return a <span class="type">vector</span>
containing exactly one element.</p><p>This is of much greater concern when dealing with more intricate templates. Consider
the following trivial template function:</p><pre class="programlisting">template<typename T>
T Process()
{
T t{};
//do stuff with t;
return T{t};
}</pre><p>This function creates a temporary, does some processing, and returns a copy of it.
This function requires that <span class="type">T</span> be DefaultConstructible and
CopyConstructible, in addition to whatever <span class="quote">“<span class="quote">do stuff with t</span>”</span>
requires.</p><p>The problem is the last line. This line <span class="emphasis"><em>may</em></span> violate the concept
constraint. Why? Because there is no guarantee that <span class="type">T</span> does
<span class="emphasis"><em>not</em></span> have an <span class="type">initializer_list</span> constructor that can
match with a <span class="type">T</span>. For an example of such a class, consider
<span class="type">std::vector<std::function<void()>></span> as our <span class="type">T</span>.</p><p>The problem is that <span class="type">std::function</span> has a non-explicit constructor that can
take <span class="emphasis"><em>any</em></span> type that is CopyConstructible. And
<span class="type">std::vector<std::function></span> is CopyConstructible. Therefore, this
will call the initializer_list constructor. But the template function should not be
calling the initializer list constructor; it's not part of the allowed interface to T.
Therefore, <code class="function">Process</code> violates the concept constraint, through no
fault on the user's part.</p><p>What this means is that you cannot use uniform initialization in generic code where
the exact type of the object being constructed is derived from a template parameter.
This is because there is no way for the user to explicitly choose which constructors to
call.</p></div><div class="section" title="Design Overview"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e160"></a>Design Overview</h2></div></div></div><p>The idea is a bit complex, but not unreasonably so. We recognize that there are 4
possible ways that a user could want to use uniform initialization:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>Call a non-initializer_list constructor.</p></li><li class="listitem"><p>Call an initializer_list constructor.</p></li><li class="listitem"><p>Call a non-initializer_list constructor where applicable; if none fit, call an
initializer_list constructor.</p></li><li class="listitem"><p>Call an initializer_list constructor where applicable; if none fit, call a
non-initializer_list constructor.</p></li></ol></div><p>These variation <span class="emphasis"><em>only</em></span> affect which constructors are considered
during overload resolution; in every other respect, they work like a regular
braced-init-list. So if they're initializing an aggregate, <span class="emphasis"><em>all of
them</em></span> will work as normal via aggregate initialization rules. The only
thing that changes, outside of the grammar that will be discussed presently, is section
13.3.1.7's list initialization overload resolution rules. They will cover the four
cases.</p><p>This means that there must be four separate types of braced-init-lists. They will all
behave the same except for how they interact with 13.3.1.7.</p><p>The big issue is how these special braced-init-lists are defined in the grammar. It
should look like this:</p><pre class="programlisting">{<special identifier>: ... }</pre><p>The <span class="quote">“<span class="quote"><code class="literal"><special identifer></code></span>”</span> is like the
<span class="quote">“<span class="quote">override</span>”</span> and <span class="quote">“<span class="quote">final</span>”</span> special identifiers in classes.
There will be four, each corresponding to a different scheme:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><span class="quote">“<span class="quote"><code class="literal">c</code></span>”</span>: Call a non-initializer_list
constructor.</p></li><li class="listitem"><p><span class="quote">“<span class="quote"><code class="literal">l</code></span>”</span>: Call an initializer_list
constructor.</p></li><li class="listitem"><p><span class="quote">“<span class="quote"><code class="literal">cl</code></span>”</span>: Call a non-initializer_list constructor
where applicable; if none fit, call an initializer_list constructor.</p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>I am not entirely convinced that we need this one. I personally really
like the idea of forcing you to choose which set of constructors a
braced-init-list should call. But since we can't get rid of the old syntax,
orthogonality requires that we also allow the opposite convention to
work.</p></div></li><li class="listitem"><p><span class="quote">“<span class="quote"><code class="literal">lc</code></span>”</span>: Call an initializer_list constructor
where applicable; if none fit, call a non-initializer_list constructor.
Equivalent to <span class="quote">“<span class="quote"><code class="literal">{}</code></span>”</span></p></li></ol></div></div><div class="section" title="Impact on the Standard"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e235"></a>Impact on the Standard</h2></div></div></div><p>Depending on how we want to handle the wording, we may need a new set of
<span class="quote">“<span class="quote">list-initialization</span>”</span> types. 13.3.1.7 never mentions braced-init-list;
it only operates in terms of list-initialization, which stems from a specific use of
braced-init-list. We could have it say something like <span class="quote">“<span class="quote">if the braced-init-list
that issues this constructor is one of these types, then ...</span>”</span> Or we could
provide different forms of <span class="quote">“<span class="quote">list-initialization.</span>”</span></p><p>It should cause zero backwards compatibility problems. Regular braced-init-lists
should have the same behavior as before, and the new grammar would not have been legal
before. Also, see the Design Decisions section.</p></div><div class="section" title="Design Decisions"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e250"></a>Design Decisions</h2></div></div></div><p>What follows are some alternatives and discarded designs, and the reasons for not
choosing them.</p><div class="section" title="Library vs Language"><div class="titlepage"><div><div><h3 class="title"><a name="d0e255"></a>Library vs Language</h3></div></div></div><p>Originally, I considered a library-based solution to the issue. This would have
required adding a special opaque type taken as a parameter to various calls. Since
the opaque type is different from other types, it would prevent the braced-init-list
from binding to an <span class="type">initializer_list</span> constructor, thus disambiguating
the call.</p><p>This is problematic for two reasons. First, it adds some complexity to various
container classes, as they have to prevent the user from using the opaque type as
the member or allocator types. But the primary reason that this is not a good
solution is because it only solves the problem for the standard library.</p><p>We should not ask every user who writes an <span class="type">initializer_list</span>
constructor to go though and add a suffix parameter to various functions that could
interfere. This is a problem introduced by the language, and it is best solved in
the language.</p></div><div class="section" title="Binary Choice"><div class="titlepage"><div><div><h3 class="title"><a name="d0e270"></a>Binary Choice</h3></div></div></div><p>The original design was essentially a binary choice: you pick constructors
first or initializer_list first. </p><p>This was revealed to be a bad idea, because sometimes you want something to
only consider non-init constructors or only consider initializer_list
constructors. The enumeration of the four possibilities is important, especially
for template code.</p><p>The reason why we need <span class="quote">“<span class="quote"><code class="literal">c</code></span>”</span> when we could just
use regular constructor syntax is to allow the initialization of aggregates. For
example, consider this aggregate:</p><pre class="programlisting">struct Agg
{
int x;
float y;
};</pre><p>We can initialize this via aggregate initialization:</p><pre class="programlisting">Agg agg{5, 32.3f};</pre><p>Thanks to <span class="type">std::vector</span>'s <span class="type">initializer_list</span>
constructor, we can even initialize arrays of them:</p><pre class="programlisting">std::vector<Agg> aggs{{-403, 234.0f}, {22, -19.89f}, {0, 4.2f}};</pre><p>And we can push them back into a vector:</p><pre class="programlisting">aggs.push_back({3, 92.4f});</pre><p>What we <span class="emphasis"><em>can't</em></span> do is <span class="emphasis"><em>emplace</em></span> them
back:</p><pre class="programlisting">aggs.emplace_back(3, 92.4f); //Not allowed.</pre><p>We can only initialize an aggregate in a standard library class by copy, not
directly. Why not? Because <span class="type">allocator_traits<A>::construct</span>
explicitly calls the constructor (if <span class="type">A::construct</span> doesn't exist).
And <span class="type">Agg</span> doesn't have a constructor.</p><p>With the proposed feature, we can easily redefine
<span class="type">allocator_traits<A>::construct</span> in terms of <code class="literal">{c:
params...}</code>. This will call constructors <span class="emphasis"><em>or</em></span>
employ aggregate initialization on the argument.</p><p>That wouldn't be possible without the <span class="quote">“<span class="quote">c</span>”</span> syntax. We (probably)
don't want to allow <span class="type">initializer_list</span> initialization through
<span class="type">allocator_traits<A>::construct</span>, but we should allow aggregate
initialization via it.</p></div><div class="section" title="Change the Original"><div class="titlepage"><div><div><h3 class="title"><a name="d0e346"></a>Change the Original</h3></div></div></div><p>There was an alternate design to resolve the issue. Simply declare that
non-<span class="type">initializer_list</span> constructors have priority, instead of the
other way around. This would make these completely unambiguous:</p><pre class="programlisting">std::vector<int> v1{20};
std::vector<int> v2{{20}};</pre><p><span class="type">v1</span> is using the <span class="type">size_type</span> constructor. <span class="type">v2</span>
is clearly calling a single-argument constructor using a braced-init-list.</p><p>The obvious problem with this is that it is a breaking change and a
<span class="emphasis"><em>silent</em></span> one at that.</p><p>Even worse, it doesn't look uniform:</p><pre class="programlisting">std::array<int, 6> a1 = {1, 2, 3, 4, 5, 6}; //Brace elision removes the extra pair.
std::vector<int> v1 = {1, 2, 3, 4, 5, 6}; //Brace "elision" possible.
std::array<int, 1> a2 = {1}; //Brace elision still works.
std::vector<int> v2 = {1}; //Brace "elision" no longer possible due to conflict. Does the wrong thing.</pre><p>Honestly, this would be the preferable solution, if it were not a breaking change.
But it is, so we probably shouldn't do it.</p><p>There is a way to use this to make a <span class="emphasis"><em>noisy</em></span> breaking change.
If we effectively make {} equivalent to {<span class="quote">“<span class="quote">l</span>”</span>}, disallowing
non-initializer_list constructors, then the compiler will at least complain about
the problem. This would force the user to go through and annotate their expectations
directly. And we have more uniformity: {} means initialize-from-list, while {:}
means possibly call constructors.</p></div><div class="section" title="Possible Addendum"><div class="titlepage"><div><div><h3 class="title"><a name="d0e385"></a>Possible Addendum</h3></div></div></div><p>Presently, explicit constructors cannot be called in copy-list-initialization
contexts. This can force the use of a long, complex type in places where it is not
needed. For example:</p><pre class="programlisting">LongComplexFunctionReturnType<ThatIShouldn,tTypeAgain> FuncName(...)
{
//Compute stuff.
return LongComplexFunctionReturnType<ThatIShouldn,tTypeAgain>{params};
}</pre><p>The proposed syntax of providing parameters to the braced-init-list means that we
could have additional parameters that allow a braced-init-list to call explicit
constructors even in copy-list-initialization contexts:</p><pre class="programlisting">LongComplexFunctionReturnType<ThatIShouldn,tTypeAgain> FuncName(...)
{
//Compute stuff.
return {explicit c: params};
}</pre><p>The main reason for introducing the copy-list-initialization to begin with was due
to concerns that not having it effectively made <code class="literal">explicit</code>
pointless, since people could easily end-run around it. This allows us to not have
to repeat the type, but we do have to at least state in our code the intent to call
<code class="literal">explicit</code> constructors.</p></div></div><div class="section" title="Technical Specifications"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e404"></a>Technical Specifications</h2></div></div></div><p></p></div><div class="section" title="Acknowledgements"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e408"></a>Acknowledgements</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Malte Skarupke: For bringing up the issue of using uniform initialization in
generic code.</p></li><li class="listitem"><p>Joël Lamotte: For coming up with the idea to use <span class="quote">“<span class="quote">{:}</span>”</span>
syntax.</p></li><li class="listitem"><p>Jeffrey Yasskin and Nikolay Ivchenkov, who offered valuable criticism of the
idea that led to the current identifier syntax.</p></li></ul></div></div><div class="section" title="References"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e424"></a>References</h2></div></div></div><p></p></div></div></body></html>
------=_Part_1757_22895013.1357359392362--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Sat, 5 Jan 2013 05:52:03 -0800 (PST)
Raw View
------=_Part_1447_10166529.1357393923390
Content-Type: text/plain; charset=ISO-8859-1
On Saturday, January 5, 2013 3:43:54 AM UTC+4, Nicol Bolas wrote:
>
>
>> According to your description, in your case an aggregate initialization
>> may take precedence over a valid ()-wise direct-initialization with other
>> meaning.
>>
>
> When? If an object has a constructor, then it is not an aggregate.
>
Aggregates may have copy/move constructors. The type of an initializer
expression may have a conversion function that would make it possible to
implicitly convert the initializer to the type of the object being
initialized: http://liveworkspace.org/code/2snMf6$0 (as I said before, this
is an exotic case).
> You're talking about a very specific problem: template type deduction of
>>> initializer lists. That's not the problem under discussion for this
>>> proposal.
>>>
>>
>> A resolution of such a "very specific problem" may conflict with your
>> proposal or (most likely) be a superior solution for actual problems that
>> your proposal could solve. I don't think that it would be wise to
>> concentrate our attention on a single issue and ignore others, because
>> suggestions for their resolution may potentially interact with each other.
>>
>
> There are only two possible solutions to this:
>
> 1: Define that a braced-init-list is deduced in a template as an
> initializer_list<T>, for some deduced type T based on some arbitrary rules.
> 2: Define that a braced-init-list is deduced as some completely new object
> with rules and behavior which is somehow magically able to be converted
> into perfectly-forwarded braced-init-list construction parameters on-demand.
>
In the second case we could use ()-wise syntax and pass initializer lists
as ordinary arguments. Note that function templates like emplace_back would
immediately get an ability to perform an aggregate initialization and
forward initializer lists to initializer-list constructors, while library
implementors, that currently use ()-wise initialization, would not need to
change anything in their code for that. This would actually imply that
()-wise initialization would be a functionally uniform initialization with
a single consistent semantics (as opposed to visually uniform {}-wise
initialization with irregular dual semantics). Isn't this a superior
alternative for your proposal?
On Saturday, January 5, 2013 7:31:23 AM UTC+4, Nicol Bolas wrote:
>
> There are really four different scenarios that you might come across with
> uniform initialization with regard to mapping a braced-init-list to a
> constructor. You might want:
>
>
> - Initializer-list constructors only.
> - Non-init-list constructors only.
> - Initializer-list, then others (the current behavior).
> - Non-init-list constructors, then init-list constructors.
>
> Each of these are very reasonable things for the user to want, and we
> should not force the user to have to live with one of these.
>
All of these 4 goals are not primary. Tasks #3 and #4 are purely contrived.
I know only two basic useful goals:
1) we want to perform an initialization wih a certain semantics (i.e. call
a constructor with a certainly defined semantics among an overloaded set of
constructors or perform an aggregate initialization and nothing else, etc.)
[Examples: a) we want to create a vector<int> object with 20
value-initialized elements, b) we want to move an object];
2) we want to perform an initialization inside a library component and let
a user of the library component to decide how exactly the initialization
shall be done [Examples: a) std::make_shared, b) a container's emplace_back
method].
For the former goal we should be able to express our intention clearly
enough. For the latter goal a user should be able to specify desirable
initialization semantics by means of an argument list for a function call,
and the encoding should be concise and clear enough.
> Therefore, if I want to create std::vector<int> with one value, I do this:
>
> std::vector<int>{l: 20};
>
That could help with the basic goal #1.
> And if I have some type T that I want to construct with a variadic
> parameter list, and I want T to be able to be an aggregate, but not to
> allow the parameter list to use initializer_list constructors:
>
> return {c: params...}; //Assuming we return a T by value.
>
That doesn't look much helpful. In general, whether the object shall be
initialized by an initializer-list constructor should be specified by a
user of the template, not by the template definition. When it would be
reasonable to do otherwise?
--
------=_Part_1447_10166529.1357393923390
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Saturday, January 5, 2013 3:43:54 AM UTC+4, Nicol Bolas wrote:<blockquot=
e class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: =
1px #ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div><br>According to your description, in your case an aggregate initiali=
zation may take precedence over a valid ()-wise direct-initialization with =
other meaning.</div></blockquote><div><br>When? If an object has a construc=
tor, then it is not an aggregate.</div></blockquote><div><br>Aggregates may=
have copy/move constructors. The type of an initializer expression may hav=
e a conversion function that would make it possible to implicitly convert t=
he initializer to the type of the object being initialized: http://livework=
space.org/code/2snMf6$0 (as I said before, this is an exotic case).<br>&nbs=
p;</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0=
..8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><blockquote class=3D"g=
mail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;=
padding-left:1ex"><blockquote class=3D"gmail_quote" style=3D"margin:0;margi=
n-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>You're talki=
ng about a very specific problem: template type deduction of initializer li=
sts. That's not the problem under discussion for this proposal.<br></div></=
blockquote><div><br>A resolution of such a "very specific problem" may conf=
lict with your proposal or (most likely) be a superior solution for actual =
problems that your proposal could solve. I don't think that it would be wis=
e to concentrate our attention on a single issue and ignore others, because=
suggestions for their resolution may potentially interact with each other.=
<br></div></blockquote><div><br>There are only two possible solutions to th=
is:<br><br>1: Define that a braced-init-list is deduced in a template as an=
initializer_list<T>, for some deduced type T based on some arbitrary=
rules.<br>2: Define that a braced-init-list is deduced as some completely =
new object with rules and behavior which is somehow magically able to be co=
nverted into perfectly-forwarded braced-init-list construction parameters o=
n-demand.<br></div></blockquote><div><br>In the second case we could use ()=
-wise syntax and pass initializer lists as ordinary arguments. Note that fu=
nction templates like emplace_back would immediately get an ability to perf=
orm an aggregate initialization and forward initializer lists to initialize=
r-list constructors, while library implementors, that currently use ()-wise=
initialization, would not need to change anything in their code for that. =
This would actually imply that ()-wise initialization would be a functional=
ly uniform initialization with a single consistent semantics (as opposed to=
visually uniform {}-wise initialization with irregular dual semantics). Is=
n't this a superior alternative for your proposal?<br><br>On Saturday, Janu=
ary 5, 2013 7:31:23 AM UTC+4, Nicol Bolas wrote:<blockquote class=3D"gmail_=
quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pa=
dding-left: 1ex;"><div>There
are really four different scenarios that you might come across with=20
uniform initialization with regard to mapping a braced-init-list to a=20
constructor. You might want:<br><br><ul><li>Initializer-list constructors o=
nly.</li><li>Non-init-list constructors only.</li><li>Initializer-list, the=
n others (the current behavior).<br></li><li>Non-init-list constructors, th=
en init-list constructors.</li></ul>Each
of these are very reasonable things for the user to want, and we should
not force the user to have to live with one of these.</div></blockquote><d=
iv><br>All of these 4 goals are not primary. Tasks #3 and #4 are purely con=
trived. I know only two basic useful goals:<br><br>1)
we want to perform an initialization wih a certain semantics (i.e. call
a constructor with a certainly defined semantics among an overloaded=20
set of constructors or perform an aggregate initialization and nothing=20
else, etc.) [Examples: a) we want to create a vector<int> object=20
with 20 value-initialized elements, b) we want to move an object];<br><br>2=
) we want to perform an initialization inside a=20
library component and let a user of the library component to decide how=20
exactly the initialization shall be done [Examples: a) std::make_shared, b)=
a=20
container's emplace_back method].<br><br>For the former goal we should=20
be able to express our intention clearly enough. For the latter goal a=20
user should be able to specify desirable initialization semantics by=20
means of an argument list for a function call, and the encoding should=20
be concise and clear enough.<br> </div><blockquote class=3D"gmail_quot=
e" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddin=
g-left: 1ex;"><div> Therefore, if I want to create std::vector<int> w=
ith one value, I do this:<br><br><div style=3D"background-color:rgb(250,250=
,250);border-color:rgb(187,187,187);border-style:solid;border-width:1px;wor=
d-wrap:break-word"><code><div><span style=3D"color:#000">std</span><span st=
yle=3D"color:#660">::</span><span style=3D"color:#000">vector</span><span s=
tyle=3D"color:#080"><int></span><span style=3D"color:#660">{</span><s=
pan style=3D"color:#000">l</span><span style=3D"color:#660">:</span><span s=
tyle=3D"color:#000"> </span><span style=3D"color:#066">20</span><span style=
=3D"color:#660">};</span><span style=3D"color:#000"><br></span></div></code=
></div></div></blockquote><div><br>That could help with the basic goal #1.<=
br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-=
left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>And
if I have some type T that I want to construct with a variadic=20
parameter list, and I want T to be able to be an aggregate, but not to=20
allow the parameter list to use initializer_list constructors:<br><br><div =
style=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);bo=
rder-style:solid;border-width:1px;word-wrap:break-word"><code><div><span st=
yle=3D"color:#008">return</span><span style=3D"color:#000"> </span><span st=
yle=3D"color:#660">{</span><span style=3D"color:#000">c</span><span style=
=3D"color:#660">:</span><span style=3D"color:#000"> </span><span style=3D"c=
olor:#008">params</span><span style=3D"color:#660">...};</span><span style=
=3D"color:#000"> </span><span style=3D"color:#800">//Assuming we retu=
rn a T by value.</span><span style=3D"color:#000"><br></span></div></code><=
/div></div></blockquote><div><br>That
doesn't look much helpful. In general, whether the object shall be initial=
ized by an=20
initializer-list constructor should be specified by a user of the template,=
not by the=20
template definition. When it would be reasonable to do=20
otherwise?</div><br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1447_10166529.1357393923390--
.
Author: Beman Dawes <bdawes@acm.org>
Date: Sat, 5 Jan 2013 09:19:16 -0500
Raw View
On Fri, Jan 4, 2013 at 11:16 PM, Nicol Bolas <jmckesson@gmail.com> wrote:
> OK, I've updated the proposal with the new {<special identifier>: } syntax.
You might want to consider changing:
It should cause zero backwards compatibility problems. Regular
braced-init-lists should have the same behavior as before, and the new
grammar would not have been legal before.
to:
The intent of the proposal is to break no existing code. Regular
braced-init-lists are intended to have the same behavior as in C++11,
and the new grammar would not have been legal in C++11.
Assuming that's what you meant, of course:-)
You might also want to add a section "Implementation experience" that
just says "None yet." While that might seem obvious, it signals that
you are aware that a proposal of this magnitude would have to be
implemented at a later stage of the process.
Cheers,
--Beman
--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sat, 5 Jan 2013 11:22:35 -0800 (PST)
Raw View
------=_Part_2273_29294786.1357413755153
Content-Type: text/plain; charset=ISO-8859-1
On Saturday, January 5, 2013 5:52:03 AM UTC-8, Nikolay Ivchenkov wrote:
>
> On Saturday, January 5, 2013 3:43:54 AM UTC+4, Nicol Bolas wrote:
>
You're talking about a very specific problem: template type deduction of
>>>> initializer lists. That's not the problem under discussion for this
>>>> proposal.
>>>>
>>>
>>> A resolution of such a "very specific problem" may conflict with your
>>> proposal or (most likely) be a superior solution for actual problems that
>>> your proposal could solve. I don't think that it would be wise to
>>> concentrate our attention on a single issue and ignore others, because
>>> suggestions for their resolution may potentially interact with each other.
>>>
>>
>> There are only two possible solutions to this:
>>
>> 1: Define that a braced-init-list is deduced in a template as an
>> initializer_list<T>, for some deduced type T based on some arbitrary rules.
>> 2: Define that a braced-init-list is deduced as some completely new
>> object with rules and behavior which is somehow magically able to be
>> converted into perfectly-forwarded braced-init-list construction parameters
>> on-demand.
>>
>
> In the second case we could use ()-wise syntax and pass initializer lists
> as ordinary arguments.
>
Except we can't do that, because () means "expression". You can't just give
() arbitrary semantics.
> Note that function templates like emplace_back would immediately get an
> ability to perform an aggregate initialization and forward initializer
> lists to initializer-list constructors, while library implementors, that
> currently use ()-wise initialization, would not need to change anything in
> their code for that. This would actually imply that ()-wise initialization
> would be a functionally uniform initialization with a single consistent
> semantics (as opposed to visually uniform {}-wise initialization with
> irregular dual semantics). Isn't this a superior alternative for your
> proposal?
>
No. Besides the syntactic reality that it wouldn't work, it would also
break various code because you then have to resolve the ambiguity between
initializer_list constructors and non-initializer_list constructors. You
know, exactly what this proposal is trying to solve with {}.
Also, it would still allow the most vexing parse. As well as prevent basic
syntax like `Type t();` from working.
> On Saturday, January 5, 2013 7:31:23 AM UTC+4, Nicol Bolas wrote:
>>
>> There are really four different scenarios that you might come across with
>> uniform initialization with regard to mapping a braced-init-list to a
>> constructor. You might want:
>>
>>
>> - Initializer-list constructors only.
>> - Non-init-list constructors only.
>> - Initializer-list, then others (the current behavior).
>> - Non-init-list constructors, then init-list constructors.
>>
>> Each of these are very reasonable things for the user to want, and we
>> should not force the user to have to live with one of these.
>>
>
> All of these 4 goals are not primary. Tasks #3 and #4 are purely contrived.
>
Considering that #3 is the *current* behavior, I suspect that others think
differently about how "contrived" it is.
> I know only two basic useful goals:
>
> 1) we want to perform an initialization wih a certain semantics (i.e. call
> a constructor with a certainly defined semantics among an overloaded set of
> constructors or perform an aggregate initialization and nothing else, etc.)
> [Examples: a) we want to create a vector<int> object with 20
> value-initialized elements, b) we want to move an object];
>
And those "certain defined semantics" come in 4 flavors. As stated above.
You *personally* may not want to do 3 or 4, but the "not you" demographic
certainly does sometimes.
2) we want to perform an initialization inside a library component and let
> a user of the library component to decide how exactly the initialization
> shall be done [Examples: a) std::make_shared, b) a container's emplace_back
> method].
>
#2 is out of scope for this discussion. How some other code performs
initialization is not the question. This is about when you, the writer of
some code, are trying to initialize some object, and you want to do so
along certain semantics. Forwarding initialization is a separate problem.
It's also a rather dubious request. We don't have ways to control how an
object gets used externally in any other way. If you call
std::vector<T>::push_back, the type T must have a copy constructor. And so
forth. You can't call push_back without that and expect it to work.
In every other case, the template *itself* puts restrictions on the
interface for the types of its arguments. It defines exactly what your type
needs to implement. Why should the user suddenly and magically have control
over this for initialization when in any other scenario they would have to
defer to the template's definition?
For the former goal we should be able to express our intention clearly
> enough. For the latter goal a user should be able to specify desirable
> initialization semantics by means of an argument list for a function call,
> and the encoding should be concise and clear enough.
>
>
>> Therefore, if I want to create std::vector<int> with one value, I do this:
>>
>> std::vector<int>{l: 20};
>>
>
> That could help with the basic goal #1.
>
>
>> And if I have some type T that I want to construct with a variadic
>> parameter list, and I want T to be able to be an aggregate, but not to
>> allow the parameter list to use initializer_list constructors:
>>
>> return {c: params...}; //Assuming we return a T by value.
>>
>
> That doesn't look much helpful. In general, whether the object shall be
> initialized by an initializer-list constructor should be specified by a
> user of the template, not by the template definition. When it would be
> reasonable to do otherwise?
>
>
The presence of an initializer_list constructor would be part of the *
concept* that the template places on its types. Just like std::vector
requires that T be at least MoveConstructible. How an object can be used is
defined by the template definition, not the user. Initialization is part of
how an object is to be used.
If a template says, "I expect to be able to call {lc: ...} to initialize
the type you pass for some set of values", then you must provide a type
that will be able to be initialized with that braced-init-list. If you
don't, that's an error on your part. You don't get to decide how a template
uses your type; the template decides that. Initialization is no different.
The moment you hand initialization duties off to someone else, you give up
the right to decide exactly how to initialize it.
--
------=_Part_2273_29294786.1357413755153
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Saturday, January 5, 2013 5:52:03 AM UTC-8, Nikolay Ivchenkov wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">On Saturday, January 5, 20=
13 3:43:54 AM UTC+4, Nicol Bolas wrote: <br></blockquote><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"marg=
in:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><blockq=
uote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:=
1px #ccc solid;padding-left:1ex"><blockquote class=3D"gmail_quote" style=3D=
"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><d=
iv>You're talking about a very specific problem: template type deduction of=
initializer lists. That's not the problem under discussion for this propos=
al.<br></div></blockquote><div><br>A resolution of such a "very specific pr=
oblem" may conflict with your proposal or (most likely) be a superior solut=
ion for actual problems that your proposal could solve. I don't think that =
it would be wise to concentrate our attention on a single issue and ignore =
others, because suggestions for their resolution may potentially interact w=
ith each other.<br></div></blockquote><div><br>There are only two possible =
solutions to this:<br><br>1: Define that a braced-init-list is deduced in a=
template as an initializer_list<T>, for some deduced type T based on=
some arbitrary rules.<br>2: Define that a braced-init-list is deduced as s=
ome completely new object with rules and behavior which is somehow magicall=
y able to be converted into perfectly-forwarded braced-init-list constructi=
on parameters on-demand.<br></div></blockquote><div><br>In the second case =
we could use ()-wise syntax and pass initializer lists as ordinary argument=
s.</div></blockquote><div><br>Except we can't do that, because () means "ex=
pression". You can't just give () arbitrary semantics.<br> </div><bloc=
kquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-l=
eft: 1px #ccc solid;padding-left: 1ex;"><div>Note that function templates l=
ike emplace_back would immediately get an ability to perform an aggregate i=
nitialization and forward initializer lists to initializer-list constructor=
s, while library implementors, that currently use ()-wise initialization, w=
ould not need to change anything in their code for that. This would actuall=
y imply that ()-wise initialization would be a functionally uniform initial=
ization with a single consistent semantics (as opposed to visually uniform =
{}-wise initialization with irregular dual semantics). Isn't this a superio=
r alternative for your proposal?<br></div></blockquote><div><br>No. Besides=
the syntactic reality that it wouldn't work, it would also break various c=
ode because you then have to resolve the ambiguity between initializer_list=
constructors and non-initializer_list constructors. You know, exactly what=
this proposal is trying to solve with {}.<br><br>Also, it would still allo=
w the most vexing parse. As well as prevent basic syntax like `Type t();` f=
rom working.<br> </div><blockquote class=3D"gmail_quote" style=3D"marg=
in: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><d=
iv>On Saturday, January 5, 2013 7:31:23 AM UTC+4, Nicol Bolas wrote:<blockq=
uote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:=
1px #ccc solid;padding-left:1ex"><div>There
are really four different scenarios that you might come across with=20
uniform initialization with regard to mapping a braced-init-list to a=20
constructor. You might want:<br><br><ul><li>Initializer-list constructors o=
nly.</li><li>Non-init-list constructors only.</li><li>Initializer-list, the=
n others (the current behavior).<br></li><li>Non-init-list constructors, th=
en init-list constructors.</li></ul>Each
of these are very reasonable things for the user to want, and we should
not force the user to have to live with one of these.</div></blockquote><d=
iv><br>All of these 4 goals are not primary. Tasks #3 and #4 are purely con=
trived.</div></div></blockquote><div><br>Considering that #3 is the <i>curr=
ent</i> behavior, I suspect that others think differently about how "contri=
ved" it is.<br> </div><blockquote class=3D"gmail_quote" style=3D"margi=
n: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><di=
v><div> I know only two basic useful goals:<br><br>1)
we want to perform an initialization wih a certain semantics (i.e. call
a constructor with a certainly defined semantics among an overloaded=20
set of constructors or perform an aggregate initialization and nothing=20
else, etc.) [Examples: a) we want to create a vector<int> object=20
with 20 value-initialized elements, b) we want to move an object];<br></div=
></div></blockquote><div><br>And those "certain defined semantics" come in =
4 flavors. As stated above. You <i>personally</i> may not want to do 3 or 4=
, but the "not you" demographic certainly does sometimes.<br><br></div><blo=
ckquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-=
left: 1px #ccc solid;padding-left: 1ex;"><div><div>2) we want to perform an=
initialization inside a=20
library component and let a user of the library component to decide how=20
exactly the initialization shall be done [Examples: a) std::make_shared, b)=
a=20
container's emplace_back method].<br></div></div></blockquote><div><br>#2 i=
s out of scope for this discussion. How some other code performs initializa=
tion is not the question. This is about when you, the writer of some code, =
are trying to initialize some object, and you want to do so along certain s=
emantics. Forwarding initialization is a separate problem.<br><br>It's also=
a rather dubious request. We don't have ways to control how an object gets=
used externally in any other way. If you call std::vector<T>::push_b=
ack, the type T must have a copy constructor. And so forth. You can't call =
push_back without that and expect it to work.<br><br>In every other case, t=
he template <i>itself</i> puts restrictions on the interface for the types =
of its arguments. It defines exactly what your type needs to implement. Why=
should the user suddenly and magically have control over this for initiali=
zation when in any other scenario they would have to defer to the template'=
s definition?<br><br></div><blockquote class=3D"gmail_quote" style=3D"margi=
n: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><di=
v><div>For the former goal we should=20
be able to express our intention clearly enough. For the latter goal a=20
user should be able to specify desirable initialization semantics by=20
means of an argument list for a function call, and the encoding should=20
be concise and clear enough.<br> </div><blockquote class=3D"gmail_quot=
e" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-l=
eft:1ex"><div> Therefore, if I want to create std::vector<int> with o=
ne value, I do this:<br><br><div style=3D"background-color:rgb(250,250,250)=
;border-color:rgb(187,187,187);border-style:solid;border-width:1px;word-wra=
p:break-word"><code><div><span style=3D"color:#000">std</span><span style=
=3D"color:#660">::</span><span style=3D"color:#000">vector</span><span styl=
e=3D"color:#080"><int></span><span style=3D"color:#660">{</span><span=
style=3D"color:#000">l</span><span style=3D"color:#660">:</span><span styl=
e=3D"color:#000"> </span><span style=3D"color:#066">20</span><span style=3D=
"color:#660">};</span><span style=3D"color:#000"><br></span></div></code></=
div></div></blockquote><div><br>That could help with the basic goal #1.<br>=
</div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left=
:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>And
if I have some type T that I want to construct with a variadic=20
parameter list, and I want T to be able to be an aggregate, but not to=20
allow the parameter list to use initializer_list constructors:<br><br><div =
style=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);bo=
rder-style:solid;border-width:1px;word-wrap:break-word"><code><div><span st=
yle=3D"color:#008">return</span><span style=3D"color:#000"> </span><span st=
yle=3D"color:#660">{</span><span style=3D"color:#000">c</span><span style=
=3D"color:#660">:</span><span style=3D"color:#000"> </span><span style=3D"c=
olor:#008">params</span><span style=3D"color:#660">...};</span><span style=
=3D"color:#000"> </span><span style=3D"color:#800">//Assuming we retu=
rn a T by value.</span><span style=3D"color:#000"><br></span></div></code><=
/div></div></blockquote><div><br>That
doesn't look much helpful. In general, whether the object shall be initial=
ized by an=20
initializer-list constructor should be specified by a user of the template,=
not by the=20
template definition. When it would be reasonable to do=20
otherwise?<br></div><br></div></blockquote><div><br>The presence of an init=
ializer_list constructor would be part of the <i>concept</i> that the templ=
ate places on its types. Just like std::vector requires that T be at least =
MoveConstructible. How an object can be used is defined by the template def=
inition, not the user. Initialization is part of how an object is to be use=
d.<br><br>If a template says, "I expect to be able to call {lc: ...} to ini=
tialize the type you pass for some set of values", then you must provide a =
type that will be able to be initialized with that braced-init-list. If you=
don't, that's an error on your part. You don't get to decide how a templat=
e uses your type; the template decides that. Initialization is no different=
..<br><br>The moment you hand initialization duties off to someone else, you=
give up the right to decide exactly how to initialize it.<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_2273_29294786.1357413755153--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Sat, 5 Jan 2013 14:04:26 -0800 (PST)
Raw View
------=_Part_1725_17823427.1357423466909
Content-Type: text/plain; charset=ISO-8859-1
On Saturday, January 5, 2013 11:22:35 PM UTC+4, Nicol Bolas wrote:
> On Saturday, January 5, 2013 5:52:03 AM UTC-8, Nikolay Ivchenkov wrote:
>>
>> On Saturday, January 5, 2013 3:43:54 AM UTC+4, Nicol Bolas wrote:
>>
> 2: Define that a braced-init-list is deduced as some completely new object
>>> with rules and behavior which is somehow magically able to be converted
>>> into perfectly-forwarded braced-init-list construction parameters on-demand.
>>>
>>
>> In the second case we could use ()-wise syntax and pass initializer lists
>> as ordinary arguments.
>>
>
> Except we can't do that, because () means "expression". You can't just
> give () arbitrary semantics.
>
We already use ()-wise syntax for direct-initialization.
> Note that function templates like emplace_back would immediately get an
>> ability to perform an aggregate initialization and forward initializer
>> lists to initializer-list constructors, while library implementors, that
>> currently use ()-wise initialization, would not need to change anything in
>> their code for that. This would actually imply that ()-wise initialization
>> would be a functionally uniform initialization with a single consistent
>> semantics (as opposed to visually uniform {}-wise initialization with
>> irregular dual semantics). Isn't this a superior alternative for your
>> proposal?
>>
>
> No. Besides the syntactic reality that it wouldn't work, it would also
> break various code because you then have to resolve the ambiguity between
> initializer_list constructors and non-initializer_list constructors.
>
The model with ~{items} shown above seems to be pretty unambiguous.
There are really four different scenarios that you might come across with
>>> uniform initialization with regard to mapping a braced-init-list to a
>>> constructor. You might want:
>>>
>>> - Initializer-list constructors only.
>>> - Non-init-list constructors only.
>>> - Initializer-list, then others (the current behavior).
>>> - Non-init-list constructors, then init-list constructors.
>>>
>>> Each of these are very reasonable things for the user to want, and we
>>> should not force the user to have to live with one of these.
>>>
>>
>> All of these 4 goals are not primary. Tasks #3 and #4 are purely
>> contrived.
>>
>
> Considering that #3 is the *current* behavior, I suspect that others
> think differently about how "contrived" it is.
>
Do you see the difference between the behavior of a tool and goals of a
programmer?
> I know only two basic useful goals:
>>
>> 1) we want to perform an initialization wih a certain semantics (i.e.
>> call a constructor with a certainly defined semantics among an overloaded
>> set of constructors or perform an aggregate initialization and nothing
>> else, etc.) [Examples: a) we want to create a vector<int> object with 20
>> value-initialized elements, b) we want to move an object];
>>
>
> And those "certain defined semantics" come in 4 flavors.
>
There is nothing common between desirable semantics and the encoding rules
that allow a compiler to determine the desirable interpretation of the
program. A subset of considered constructors and the order in which they
are considered are related to the encoding rules and they don't constitute
any goals of ordinary programmers.
> 2) we want to perform an initialization inside a library component and let
>> a user of the library component to decide how exactly the initialization
>> shall be done [Examples: a) std::make_shared, b) a container's emplace_back
>> method].
>>
>
> #2 is out of scope for this discussion. How some other code performs
> initialization is not the question. This is about when you, the writer of
> some code, are trying to initialize some object, and you want to do so
> along certain semantics. Forwarding initialization is a separate problem.
>
> It's also a rather dubious request. We don't have ways to control how an
> object gets used externally in any other way.
>
std::make_shared and emplace_back just don't need to know that.
> If you call std::vector<T>::push_back, the type T must have a copy
> constructor. And so forth. You can't call push_back without that and expect
> it to work.
>
> In every other case, the template *itself* puts restrictions on the
> interface for the types of its arguments. It defines exactly what your type
> needs to implement. Why should the user suddenly and magically have control
> over this for initialization when in any other scenario they would have to
> defer to the template's definition?
>
I was talking about forwarding, because that your code sample looks like a
case of forwarding. I could incorrectly interpret the intention, but that's
because the code is too abstract. It would be interesting to see real world
examples.
If a template says, "I expect to be able to call {lc: ...} to initialize
> the type you pass for some set of values"
Usually requirements imposed on template arguments are not arbitrary, they
reflect (ideally minimal) conditions under which the desirable semantics
can be implemented. Could you provide an example of an underlying task for
which "I expect to be able to call {lc: ...} to initialize the type you
pass for some set of values" would be a reasonable condition?
--
------=_Part_1725_17823427.1357423466909
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Saturday, January 5, 2013 11:22:35 PM UTC+4, Nicol Bolas wrote:<br><bloc=
kquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-l=
eft: 1px #ccc solid;padding-left: 1ex;">On Saturday, January 5, 2013 5:52:0=
3 AM UTC-8, Nikolay Ivchenkov wrote:<blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
>On Saturday, January 5, 2013 3:43:54 AM UTC+4, Nicol Bolas wrote: <br></bl=
ockquote><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.=
8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class=3D"gmail=
_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padd=
ing-left:1ex"><div>2: Define that a braced-init-list is deduced as some com=
pletely new object with rules and behavior which is somehow magically able =
to be converted into perfectly-forwarded braced-init-list construction para=
meters on-demand.<br></div></blockquote><div><br>In the second case we coul=
d use ()-wise syntax and pass initializer lists as ordinary arguments.</div=
></blockquote><div><br>Except we can't do that, because () means "expressio=
n". You can't just give () arbitrary semantics.<br></div></blockquote><div>=
<br>We already use ()-wise syntax for direct-initialization.<br> </div=
><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bo=
rder-left: 1px #ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_qu=
ote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding=
-left:1ex"><div>Note that function templates like emplace_back would immedi=
ately get an ability to perform an aggregate initialization and forward ini=
tializer lists to initializer-list constructors, while library implementors=
, that currently use ()-wise initialization, would not need to change anyth=
ing in their code for that. This would actually imply that ()-wise initiali=
zation would be a functionally uniform initialization with a single consist=
ent semantics (as opposed to visually uniform {}-wise initialization with i=
rregular dual semantics). Isn't this a superior alternative for your propos=
al?<br></div></blockquote><div><br>No. Besides the syntactic reality that i=
t wouldn't work, it would also break various code because you then have to =
resolve the ambiguity between initializer_list constructors and non-initial=
izer_list constructors.</div></blockquote><div><br>The model with ~{items} =
shown above seems to be pretty unambiguous.<br><br></div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"marg=
in:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div><b=
lockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-=
left:1px #ccc solid;padding-left:1ex"><div>There
are really four different scenarios that you might come across with=20
uniform initialization with regard to mapping a braced-init-list to a=20
constructor. You might want:<br><ul><li>Initializer-list constructors only.=
</li><li>Non-init-list constructors only.</li><li>Initializer-list, then ot=
hers (the current behavior).<br></li><li>Non-init-list constructors, then i=
nit-list constructors.</li></ul>Each
of these are very reasonable things for the user to want, and we should
not force the user to have to live with one of these.</div></blockquote><d=
iv><br>All of these 4 goals are not primary. Tasks #3 and #4 are purely con=
trived.</div></div></blockquote><div><br>Considering that #3 is the <i>curr=
ent</i> behavior, I suspect that others think differently about how "contri=
ved" it is.<br></div></blockquote><div><br>Do you see the difference betwee=
n the behavior of a tool and goals of a programmer?<br> </div><blockqu=
ote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left=
: 1px #ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex=
"><div><div> I know only two basic useful goals:<br><br>1)
we want to perform an initialization wih a certain semantics (i.e. call
a constructor with a certainly defined semantics among an overloaded=20
set of constructors or perform an aggregate initialization and nothing=20
else, etc.) [Examples: a) we want to create a vector<int> object=20
with 20 value-initialized elements, b) we want to move an object];<br></div=
></div></blockquote><div><br>And those "certain defined semantics" come in =
4 flavors.</div></blockquote><div><br>There is nothing common between desir=
able semantics and the encoding rules that allow a compiler to determine th=
e desirable interpretation of the program. A subset of considered construct=
ors and the order in which they are considered are related to the encoding =
rules and they don't constitute any goals of ordinary programmers.<br> =
;</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.=
8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div></div><blockquote =
class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #=
ccc solid;padding-left:1ex"><div><div>2) we want to perform an initializati=
on inside a=20
library component and let a user of the library component to decide how=20
exactly the initialization shall be done [Examples: a) std::make_shared, b)=
a=20
container's emplace_back method].<br></div></div></blockquote><div><br>#2 i=
s out of scope for this discussion. How some other code performs initializa=
tion is not the question. This is about when you, the writer of some code, =
are trying to initialize some object, and you want to do so along certain s=
emantics. Forwarding initialization is a separate problem.<br><br>It's also=
a rather dubious request. We don't have ways to control how an object gets=
used externally in any other way.</div></blockquote><div><br>std::make_sha=
red and emplace_back just don't need to know that.<br> </div><blockquo=
te class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left:=
1px #ccc solid;padding-left: 1ex;"><div> If you call std::vector<T>:=
:push_back, the type T must have a copy constructor. And so forth. You can'=
t call push_back without that and expect it to work.<br><br>In every other =
case, the template <i>itself</i> puts restrictions on the interface for the=
types of its arguments. It defines exactly what your type needs to impleme=
nt. Why should the user suddenly and magically have control over this for i=
nitialization when in any other scenario they would have to defer to the te=
mplate's definition?<br></div></blockquote><div><br>I was talking about for=
warding, because that your code sample looks like a case of forwarding. I c=
ould incorrectly interpret the intention, but that's because the code is to=
o abstract. It would be interesting to see real world examples.<br><br></di=
v><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;">If a template says, "I expec=
t to be able to call {lc: ...} to initialize the type you pass for some set=
of values"</blockquote><div><br>Usually requirements imposed on template a=
rguments are not arbitrary, they reflect (ideally minimal) conditions under=
which the desirable semantics can be implemented. Could you provide an exa=
mple of an underlying task for which "I expect to be able to call {lc: ...}=
to initialize the type you pass for some set of values" would be a reasona=
ble condition?<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1725_17823427.1357423466909--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sat, 5 Jan 2013 15:02:01 -0800 (PST)
Raw View
------=_Part_483_16240793.1357426921501
Content-Type: text/plain; charset=ISO-8859-1
On Saturday, January 5, 2013 2:04:26 PM UTC-8, Nikolay Ivchenkov wrote:
>
> On Saturday, January 5, 2013 11:22:35 PM UTC+4, Nicol Bolas wrote:
>
>> On Saturday, January 5, 2013 5:52:03 AM UTC-8, Nikolay Ivchenkov wrote:
>>>
>>> On Saturday, January 5, 2013 3:43:54 AM UTC+4, Nicol Bolas wrote:
>>>
>> 2: Define that a braced-init-list is deduced as some completely new
>>>> object with rules and behavior which is somehow magically able to be
>>>> converted into perfectly-forwarded braced-init-list construction parameters
>>>> on-demand.
>>>>
>>>
>>> In the second case we could use ()-wise syntax and pass initializer
>>> lists as ordinary arguments.
>>>
>>
>> Except we can't do that, because () means "expression". You can't just
>> give () arbitrary semantics.
>>
>
> We already use ()-wise syntax for direct-initialization.
>
Except for when it looks like a function definition. And you must
explicitly use a typename when using it. Again, you seem to be ignoring the
reasons why we *want* uniform initialization syntax.
> Note that function templates like emplace_back would immediately get an
>>> ability to perform an aggregate initialization and forward initializer
>>> lists to initializer-list constructors, while library implementors, that
>>> currently use ()-wise initialization, would not need to change anything in
>>> their code for that. This would actually imply that ()-wise initialization
>>> would be a functionally uniform initialization with a single consistent
>>> semantics (as opposed to visually uniform {}-wise initialization with
>>> irregular dual semantics). Isn't this a superior alternative for your
>>> proposal?
>>>
>>
>> No. Besides the syntactic reality that it wouldn't work, it would also
>> break various code because you then have to resolve the ambiguity between
>> initializer_list constructors and non-initializer_list constructors.
>>
>
> The model with ~{items} shown above seems to be pretty unambiguous.
>
First, the proposal has {l:}, which can have those semantics in template
deduction situations. More importantly, that doesn't solve the problem,
because you don't provide a mechanism equivalent to {c:}. Or to {cl:},
which is also desirable.
There are really four different scenarios that you might come across with
>>>> uniform initialization with regard to mapping a braced-init-list to a
>>>> constructor. You might want:
>>>>
>>>> - Initializer-list constructors only.
>>>> - Non-init-list constructors only.
>>>> - Initializer-list, then others (the current behavior).
>>>> - Non-init-list constructors, then init-list constructors.
>>>>
>>>> Each of these are very reasonable things for the user to want, and we
>>>> should not force the user to have to live with one of these.
>>>>
>>>
>>> All of these 4 goals are not primary. Tasks #3 and #4 are purely
>>> contrived.
>>>
>>
>> Considering that #3 is the *current* behavior, I suspect that others
>> think differently about how "contrived" it is.
>>
>
> Do you see the difference between the behavior of a tool and goals of a
> programmer?
>
I don't see what you're getting at here.
I know only two basic useful goals:
>>>
>>> 1) we want to perform an initialization wih a certain semantics (i.e.
>>> call a constructor with a certainly defined semantics among an overloaded
>>> set of constructors or perform an aggregate initialization and nothing
>>> else, etc.) [Examples: a) we want to create a vector<int> object with 20
>>> value-initialized elements, b) we want to move an object];
>>>
>>
>> And those "certain defined semantics" come in 4 flavors.
>>
>
> There is nothing common between desirable semantics and the encoding rules
> that allow a compiler to determine the desirable interpretation of the
> program. A subset of considered constructors and the order in which they
> are considered are related to the encoding rules and they don't constitute
> any goals of ordinary programmers.
>
How not? What the compiler does is very much a part of the goals of
"ordinary programmers". The whole point of adding language features is to
provide mechanisms for programmers to more directly express their intents
and desires.
How the compiler decides which constructor to call is very much a part of
the goal of any programmer, because it informs which tool the programmer
can use. The point of this feature is to allow programmers to use {} more
effectively by giving them control over which constructors will be
considered.
2) we want to perform an initialization inside a library component and let
>>> a user of the library component to decide how exactly the initialization
>>> shall be done [Examples: a) std::make_shared, b) a container's emplace_back
>>> method].
>>>
>>
>> #2 is out of scope for this discussion. How some other code performs
>> initialization is not the question. This is about when you, the writer of
>> some code, are trying to initialize some object, and you want to do so
>> along certain semantics. Forwarding initialization is a separate problem.
>>
>> It's also a rather dubious request. We don't have ways to control how an
>> object gets used externally in any other way.
>>
>
> std::make_shared and emplace_back just don't need to know that.
>
But that's what you asked for: "user of the library component to decide how
exactly the initialization shall be done" That's external (ie: not defined
within the function) control over how an object gets used. So do you want
external control over how a template type is initialized (ie: used) or do
you not?
If you call std::vector<T>::push_back, the type T must have a copy
>> constructor. And so forth. You can't call push_back without that and expect
>> it to work.
>>
>> In every other case, the template *itself* puts restrictions on the
>> interface for the types of its arguments. It defines exactly what your type
>> needs to implement. Why should the user suddenly and magically have control
>> over this for initialization when in any other scenario they would have to
>> defer to the template's definition?
>>
>
> I was talking about forwarding, because that your code sample looks like a
> case of forwarding. I could incorrectly interpret the intention, but that's
> because the code is too abstract. It would be interesting to see real world
> examples.
>
> If a template says, "I expect to be able to call {lc: ...} to initialize
>> the type you pass for some set of values"
>
>
> Usually requirements imposed on template arguments are not arbitrary, they
> reflect (ideally minimal) conditions under which the desirable semantics
> can be implemented. Could you provide an example of an underlying task for
> which "I expect to be able to call {lc: ...} to initialize the type you
> pass for some set of values" would be a reasonable condition?
>
emplace. make_shared. make_unique. Indeed, *any* function that forwards
parameters for initialization purposes specifies as part of its concept how
it wants to initialize the type. A good initialization forwarding function
would use either {c:} (to force you to always use initializer_lists
explicitly) or {cl:}, so that you could use aggregates with them.
As I stated in the proposal, std::allocator_traits::construct could be
redefined in terms of {c:} instead of non-list initialization, so that
users can use aggregates with them.
--
------=_Part_483_16240793.1357426921501
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Saturday, January 5, 2013 2:04:26 PM UTC-8, Nikolay Ivchenkov wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">On Saturday, January 5, 20=
13 11:22:35 PM UTC+4, Nicol Bolas wrote:<br><blockquote class=3D"gmail_quot=
e" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-l=
eft:1ex">On Saturday, January 5, 2013 5:52:03 AM UTC-8, Nikolay Ivchenkov w=
rote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;=
border-left:1px #ccc solid;padding-left:1ex">On Saturday, January 5, 2013 3=
:43:54 AM UTC+4, Nicol Bolas wrote: <br></blockquote><blockquote class=3D"g=
mail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;=
padding-left:1ex"><blockquote class=3D"gmail_quote" style=3D"margin:0;margi=
n-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>2: Define th=
at a braced-init-list is deduced as some completely new object with rules a=
nd behavior which is somehow magically able to be converted into perfectly-=
forwarded braced-init-list construction parameters on-demand.<br></div></bl=
ockquote><div><br>In the second case we could use ()-wise syntax and pass i=
nitializer lists as ordinary arguments.</div></blockquote><div><br>Except w=
e can't do that, because () means "expression". You can't just give () arbi=
trary semantics.<br></div></blockquote><div><br>We already use ()-wise synt=
ax for direct-initialization.<br></div></blockquote><div><br>Except for whe=
n it looks like a function definition. And you must explicitly use a typena=
me when using it. Again, you seem to be ignoring the reasons why we <i>want=
</i> uniform initialization syntax.<br> <br></div><blockquote class=3D=
"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc s=
olid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"margin:=
0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquot=
e class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px=
#ccc solid;padding-left:1ex"><div>Note that function templates like emplac=
e_back would immediately get an ability to perform an aggregate initializat=
ion and forward initializer lists to initializer-list constructors, while l=
ibrary implementors, that currently use ()-wise initialization, would not n=
eed to change anything in their code for that. This would actually imply th=
at ()-wise initialization would be a functionally uniform initialization wi=
th a single consistent semantics (as opposed to visually uniform {}-wise in=
itialization with irregular dual semantics). Isn't this a superior alternat=
ive for your proposal?<br></div></blockquote><div><br>No. Besides the synta=
ctic reality that it wouldn't work, it would also break various code becaus=
e you then have to resolve the ambiguity between initializer_list construct=
ors and non-initializer_list constructors.</div></blockquote><div><br>The m=
odel with ~{items} shown above seems to be pretty unambiguous.<br></div></b=
lockquote><div><br>First, the proposal has {l:}, which can have those seman=
tics in template deduction situations. More importantly, that doesn't solve=
the problem, because you don't provide a mechanism equivalent to {c:}. Or =
to {cl:}, which is also desirable.<br><br></div><blockquote class=3D"gmail_=
quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pa=
dding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"margin:0;margi=
n-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><div><blockquote class=3D"gmail_quote" style=3D"marg=
in:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>Th=
ere
are really four different scenarios that you might come across with=20
uniform initialization with regard to mapping a braced-init-list to a=20
constructor. You might want:<br><ul><li>Initializer-list constructors only.=
</li><li>Non-init-list constructors only.</li><li>Initializer-list, then ot=
hers (the current behavior).<br></li><li>Non-init-list constructors, then i=
nit-list constructors.</li></ul>Each
of these are very reasonable things for the user to want, and we should
not force the user to have to live with one of these.</div></blockquote><d=
iv><br>All of these 4 goals are not primary. Tasks #3 and #4 are purely con=
trived.</div></div></blockquote><div><br>Considering that #3 is the <i>curr=
ent</i> behavior, I suspect that others think differently about how "contri=
ved" it is.<br></div></blockquote><div><br>Do you see the difference betwee=
n the behavior of a tool and goals of a programmer?<br></div></blockquote><=
div><br>I don't see what you're getting at here.<br><br></div><blockquote c=
lass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px=
#ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"=
margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><bl=
ockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-l=
eft:1px #ccc solid;padding-left:1ex"><div><div> I know only two basic usefu=
l goals:<br><br>1)
we want to perform an initialization wih a certain semantics (i.e. call
a constructor with a certainly defined semantics among an overloaded=20
set of constructors or perform an aggregate initialization and nothing=20
else, etc.) [Examples: a) we want to create a vector<int> object=20
with 20 value-initialized elements, b) we want to move an object];<br></div=
></div></blockquote><div><br>And those "certain defined semantics" come in =
4 flavors.</div></blockquote><div><br>There is nothing common between desir=
able semantics and the encoding rules that allow a compiler to determine th=
e desirable interpretation of the program. A subset of considered construct=
ors and the order in which they are considered are related to the encoding =
rules and they don't constitute any goals of ordinary programmers.<br></div=
></blockquote><div><br>How not? What the compiler does is very much a part =
of the goals of "ordinary programmers". The whole point of adding language =
features is to provide mechanisms for programmers to more directly express =
their intents and desires.<br><br>How the compiler decides which constructo=
r to call is very much a part of the goal of any programmer, because it inf=
orms which tool the programmer can use. The point of this feature is to all=
ow programmers to use {} more effectively by giving them control over which=
constructors will be considered.<br><br></div><blockquote class=3D"gmail_q=
uote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pad=
ding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin=
-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div></div><blockq=
uote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:=
1px #ccc solid;padding-left:1ex"><div><div>2) we want to perform an initial=
ization inside a=20
library component and let a user of the library component to decide how=20
exactly the initialization shall be done [Examples: a) std::make_shared, b)=
a=20
container's emplace_back method].<br></div></div></blockquote><div><br>#2 i=
s out of scope for this discussion. How some other code performs initializa=
tion is not the question. This is about when you, the writer of some code, =
are trying to initialize some object, and you want to do so along certain s=
emantics. Forwarding initialization is a separate problem.<br><br>It's also=
a rather dubious request. We don't have ways to control how an object gets=
used externally in any other way.</div></blockquote><div><br>std::make_sha=
red and emplace_back just don't need to know that.<br></div></blockquote><d=
iv><br>But that's what you asked for: "user of the library component to dec=
ide how=20
exactly the initialization shall be done" That's external (ie: not defined =
within the function) control over how an object gets used. So do you want e=
xternal control over how a template type is initialized (ie: used) or do yo=
u not?<br><br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;m=
argin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><blockquo=
te class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div> If you call std::vector<T>::push=
_back, the type T must have a copy constructor. And so forth. You can't cal=
l push_back without that and expect it to work.<br><br>In every other case,=
the template <i>itself</i> puts restrictions on the interface for the type=
s of its arguments. It defines exactly what your type needs to implement. W=
hy should the user suddenly and magically have control over this for initia=
lization when in any other scenario they would have to defer to the templat=
e's definition?<br></div></blockquote><div><br>I was talking about forwardi=
ng, because that your code sample looks like a case of forwarding. I could =
incorrectly interpret the intention, but that's because the code is too abs=
tract. It would be interesting to see real world examples.<br><br></div><bl=
ockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-l=
eft:1px #ccc solid;padding-left:1ex">If a template says, "I expect to be ab=
le to call {lc: ...} to initialize the type you pass for some set of values=
"</blockquote><div><br>Usually requirements imposed on template arguments a=
re not arbitrary, they reflect (ideally minimal) conditions under which the=
desirable semantics can be implemented. Could you provide an example of an=
underlying task for which "I expect to be able to call {lc: ...} to initia=
lize the type you pass for some set of values" would be a reasonable condit=
ion?<br></div></blockquote><div><br>emplace. make_shared. make_unique. Inde=
ed, <i>any</i> function that forwards parameters for initialization purpose=
s specifies as part of its concept how it wants to initialize the type. A g=
ood initialization forwarding function would use either {c:} (to force you =
to always use initializer_lists explicitly) or {cl:}, so that you could use=
aggregates with them.<br><br>As I stated in the proposal, std::allocator_t=
raits::construct could be redefined in terms of {c:} instead of non-list in=
itialization, so that users can use aggregates with them.<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_483_16240793.1357426921501--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Sun, 6 Jan 2013 12:03:34 -0800 (PST)
Raw View
------=_Part_214_12327526.1357502614173
Content-Type: text/plain; charset=ISO-8859-1
On Sunday, January 6, 2013 3:02:01 AM UTC+4, Nicol Bolas wrote:
>
>
>> We already use ()-wise syntax for direct-initialization.
>>
>
> Except for when it looks like a function definition.
>
The problem can be solved in two ways: by new initialization syntax or by
new declaration syntax:
simple-declaration:
....
decl-specifier-seq opt <type-id> simple-init-declarator-list
simple-init-declarator-list
simple-init-declarator
simple-init-declarator-list, simple-init-declarator
simple-init-declarator:
declarator-id initializer opt
Example:
int main()
{
<char[2]> arr(); // value-initialized object of type char[2]
}
> Again, you seem to be ignoring the reasons why we *want* uniform
> initialization syntax.
>
I prefer to compare different approaches, rather than to concentrate on a
single approach exclusively as if it would be the only possible solution.
> Note that function templates like emplace_back would immediately get an
>>>> ability to perform an aggregate initialization and forward initializer
>>>> lists to initializer-list constructors, while library implementors, that
>>>> currently use ()-wise initialization, would not need to change anything in
>>>> their code for that. This would actually imply that ()-wise initialization
>>>> would be a functionally uniform initialization with a single consistent
>>>> semantics (as opposed to visually uniform {}-wise initialization with
>>>> irregular dual semantics). Isn't this a superior alternative for your
>>>> proposal?
>>>>
>>>
>>> No. Besides the syntactic reality that it wouldn't work, it would also
>>> break various code because you then have to resolve the ambiguity between
>>> initializer_list constructors and non-initializer_list constructors.
>>>
>>
>> The model with ~{items} shown above seems to be pretty unambiguous.
>>
>
> First, the proposal has {l:}, which can have those semantics in template
> deduction situations.
>
Can {l:items} be forwarded? If not, then ~{items} with ()-wise
initialization syntax solves more issues than {l:items}:
1) disambiguation between arguments for constructor and elements of a
tuple-like entity;
2) forwarding.
> More importantly, that doesn't solve the problem, because you don't
> provide a mechanism equivalent to {c:}.
>
I'm not even sure what exactly {c:} is supposed to do.
struct X
{
X(int);
X(std::initializer_list<int>);
};
void f()
{
X x1{c: std::initializer_list<int>{20}}; // ?
X x2{c: {20}}; // ?
X x3{c: {c: 20}}; // ?
}
What should happen in these cases? Should {c: items} prevent narrowing
conversions?
void g(int n)
{
double d1{n}; // ill-formed according to the C++11 rules
double d2{c: n}; // is this well-formed or not?
}
Or to {cl:}, which is also desirable.
>
For what purposes?
> Do you see the difference between the behavior of a tool and goals of a
>> programmer?
>>
>
> I don't see what you're getting at here.
>
That explains the strange wishes.
The whole point of adding language features is to provide mechanisms for
> programmers to more directly express their intents and desires.
>
How exactly would {cl:} and {lc:} help to express intents and desires more
directly?
How the compiler decides which constructor to call is very much a part of
> the goal of any programmer, because it informs which tool the programmer
> can use
>
A goal and a way in which the goal is (or can be) reached are two different
things. If the way becomes a goal, that's something irrational.
Good readability of sources can be considered as an intermediate goal. The
readability represents the difficulty of deducing the correct
interpretation, which depends on complexity of the language rules.
> We don't have ways to control how an object gets used externally in any
>>> other way.
>>>
>>
>> std::make_shared and emplace_back just don't need to know that.
>>
>
> But that's what you asked for: "user of the library component to decide
> how exactly the initialization shall be done" That's external (ie: not
> defined within the function) control over how an object gets used. So do
> you want external control over how a template type is initialized (ie:
> used) or do you not?
>
I was talking about internal control (within the template definition) over
an external usage (on the user side).
> Usually requirements imposed on template arguments are not arbitrary, they
>> reflect (ideally minimal) conditions under which the desirable semantics
>> can be implemented. Could you provide an example of an underlying task for
>> which "I expect to be able to call {lc: ...} to initialize the type you
>> pass for some set of values" would be a reasonable condition?
>>
>
> emplace. make_shared. make_unique. Indeed, *any* function that forwards
> parameters for initialization purposes specifies as part of its concept how
> it wants to initialize the type. A good initialization forwarding function
> would use either {c:} (to force you to always use initializer_lists
> explicitly) or {cl:}, so that you could use aggregates with them.
>
There can exist a superior approach for forwarding:
struct Aggregate { int x, y; };
void f()
{
auto p1 = make_unique<Aggregate>(~{2, 1});
// aggregate initialization: new Aggregate(~{2, 1})
auto p2 = make_unique<std::vector<int>>(2, 1);
// initialization by the non-initializer-list constructor: new
std::vector<int>(2, 1)
auto p3 = make_unique<std::vector<int>>(~{2, 1});
// initialization by the initializer-list constructor: new
std::vector<int>(~{2, 1})
}
Are there any other tasks for which {lc: ...} would be useful?
--
------=_Part_214_12327526.1357502614173
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Sunday, January 6, 2013 3:02:01 AM UTC+4, Nicol Bolas wrote:<blockquote =
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1p=
x #ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D=
"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><d=
iv><br>We already use ()-wise syntax for direct-initialization.<br></div></=
blockquote><div><br>Except for when it looks like a function definition.</d=
iv></blockquote><div><br>The problem can be solved in two ways: by new init=
ialization syntax or by new declaration syntax:<br><br> s=
imple-declaration:<br> ....<br>&n=
bsp; decl-specifier-seq opt <type-id=
> simple-init-declarator-list<br><br> simple-init-decl=
arator-list<br> simple-init-decla=
rator<br> simple-init-declarator-=
list, simple-init-declarator<br><br> simple-init-declarat=
or:<br> declarator-id initializer=
opt<br><br>Example:<br><br> int main()<br> &n=
bsp; {<br> <char[2]> arr();=
// value-initialized object of type char[2]<br> }<br>&nb=
sp;</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: =
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>Again, you seem =
to be ignoring the reasons why we <i>want</i> uniform initialization syntax=
..<br></div></blockquote><div><br>I prefer to compare different approaches, =
rather than to concentrate on a single approach exclusively as if it would =
be the only possible solution.<br> </div><blockquote class=3D"gmail_qu=
ote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padd=
ing-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-=
left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><blockquote class=3D"gmail_quote" style=3D"margin:0;=
margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>Note th=
at function templates like emplace_back would immediately get an ability to=
perform an aggregate initialization and forward initializer lists to initi=
alizer-list constructors, while library implementors, that currently use ()=
-wise initialization, would not need to change anything in their code for t=
hat. This would actually imply that ()-wise initialization would be a funct=
ionally uniform initialization with a single consistent semantics (as oppos=
ed to visually uniform {}-wise initialization with irregular dual semantics=
). Isn't this a superior alternative for your proposal?<br></div></blockquo=
te><div><br>No. Besides the syntactic reality that it wouldn't work, it wou=
ld also break various code because you then have to resolve the ambiguity b=
etween initializer_list constructors and non-initializer_list constructors.=
</div></blockquote><div><br>The model with ~{items} shown above seems to be=
pretty unambiguous.<br></div></blockquote><div><br>First, the proposal has=
{l:}, which can have those semantics in template deduction situations.</di=
v></blockquote><div><br>Can {l:items} be forwarded? If not, then ~{items} w=
ith ()-wise initialization syntax solves more issues than {l:items}:<br>1) =
disambiguation between arguments for constructor and elements of a tuple-li=
ke entity;<br>2) forwarding.<br> </div><blockquote class=3D"gmail_quot=
e" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddin=
g-left: 1ex;"><div> More importantly, that doesn't solve the problem, becau=
se you don't provide a mechanism equivalent to {c:}.</div></blockquote><div=
><br>I'm not even sure what exactly {c:} is supposed to do.<br><br> &n=
bsp; struct X<br> {<br> &nbs=
p; X(int);<br> X(std:=
:initializer_list<int>);<br> };<br><br> =
void f()<br> {<br> &n=
bsp; X x1{c: std::initializer_list<int>{20}}; // ?<br> &nb=
sp; X x2{c: {20}}; // ?<br> =
X x3{c: {c: 20}}; // ?<br> }<br>=
<br>What should happen in these cases? Should {c: items} prevent narrowing =
conversions?<br><br> void g(int n)<br> =
{<br> double d1{n}; // ill-formed=
according to the C++11 rules<br> double d2=
{c: n}; // is this well-formed or not?<br> }<br><br></div=
><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bo=
rder-left: 1px #ccc solid;padding-left: 1ex;"><div> Or to {cl:}, which is a=
lso desirable.<br></div></blockquote><div><br>For what purposes?<br> <=
/div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;"><blockquote class=3D"gmai=
l_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;pad=
ding-left:1ex"><div>Do you see the difference between the behavior of a too=
l and goals of a programmer?<br></div></blockquote><div><br>I don't see wha=
t you're getting at here.<br></div></blockquote><div><br>That explains the =
strange wishes.<br><br><blockquote class=3D"gmail_quote" style=3D"margin: 0=
;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div> T=
he whole point of adding language features is to provide mechanisms for
programmers to more directly express their intents and desires.</div></blo=
ckquote><br>How exactly would {cl:} and {lc:} help to express intents and d=
esires more directly?<br><br><blockquote class=3D"gmail_quote" style=3D"mar=
gin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><=
div> How the compiler decides which constructor to call is very much a part=
=20
of the goal of any programmer, because it informs which tool the=20
programmer can use</div></blockquote><br>A goal and a way in which the goal=
is (or can be) reached are two different things. If the way becomes a goal=
, that's something irrational.<br><br>Good readability of sources can be co=
nsidered as an intermediate goal. The readability represents the difficulty=
of deducing the correct interpretation, which depends on complexity of the=
language rules.<br></div><div> <br></div><blockquote class=3D"gmail_q=
uote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pad=
ding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin=
-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><div>We don't have ways to control how an object get=
s used externally in any other way.</div></blockquote><div><br>std::make_sh=
ared and emplace_back just don't need to know that.<br></div></blockquote><=
div><br>But that's what you asked for: "user of the library component to de=
cide how=20
exactly the initialization shall be done" That's external (ie: not defined =
within the function) control over how an object gets used. So do you want e=
xternal control over how a template type is initialized (ie: used) or do yo=
u not?<br></div></blockquote><div><br>I was talking about internal control =
(within the template definition) over an external usage (on the user side).=
<br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin=
-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div> </div><b=
lockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-=
left:1px #ccc solid;padding-left:1ex"><div>Usually requirements imposed on =
template arguments are not arbitrary, they reflect (ideally minimal) condit=
ions under which the desirable semantics can be implemented. Could you prov=
ide an example of an underlying task for which "I expect to be able to call=
{lc: ...} to initialize the type you pass for some set of values" would be=
a reasonable condition?<br></div></blockquote><div><br>emplace. make_share=
d. make_unique. Indeed, <i>any</i> function that forwards parameters for in=
itialization purposes specifies as part of its concept how it wants to init=
ialize the type. A good initialization forwarding function would use either=
{c:} (to force you to always use initializer_lists explicitly) or {cl:}, s=
o that you could use aggregates with them.<br></div></blockquote><div><br>T=
here can exist a superior approach for forwarding:<br><br>  =
; struct Aggregate { int x, y; };<br><br> void f()<br>&nb=
sp; {<br> auto p1 =3D=
make_unique<Aggregate>(~{2, 1});<br> &n=
bsp; // aggregate initialization: new Aggregate(~{2, 1})<br><br> =
; auto p2 =3D make_unique<std::vecto=
r<int>>(2, 1);<br> // in=
itialization by the non-initializer-list constructor: new std::vector<in=
t>(2, 1)<br><br> auto p3 =3D m=
ake_unique<std::vector<int>>(~{2, 1});<br> &nb=
sp; // initialization by the initializer-list constructor=
: new std::vector<int>(~{2, 1})<br> }<br> <br>=
Are there any other tasks for which {lc: ...} would be useful?</div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_214_12327526.1357502614173--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sun, 6 Jan 2013 13:30:39 -0800 (PST)
Raw View
------=_Part_332_452707.1357507839713
Content-Type: text/plain; charset=ISO-8859-1
On Sunday, January 6, 2013 12:03:34 PM UTC-8, Nikolay Ivchenkov wrote:
>
> On Sunday, January 6, 2013 3:02:01 AM UTC+4, Nicol Bolas wrote:
>>
>> Again, you seem to be ignoring the reasons why we *want* uniform
>> initialization syntax.
>>
>
> I prefer to compare different approaches, rather than to concentrate on a
> single approach exclusively as if it would be the only possible solution.
>
That's wonderful; do it *elsewhere*. Please stop derailing this thread with
counterproposals; I'm trying to refine *this* proposal into something that
improves uniform initialization. Stop turning this into a "here's a
completely different initialization syntax that has completely different
semantics that are in no way shape or form uniform that we should adopt
instead" thread.
> Note that function templates like emplace_back would immediately get an
>>>>> ability to perform an aggregate initialization and forward initializer
>>>>> lists to initializer-list constructors, while library implementors, that
>>>>> currently use ()-wise initialization, would not need to change anything in
>>>>> their code for that. This would actually imply that ()-wise initialization
>>>>> would be a functionally uniform initialization with a single consistent
>>>>> semantics (as opposed to visually uniform {}-wise initialization with
>>>>> irregular dual semantics). Isn't this a superior alternative for your
>>>>> proposal?
>>>>>
>>>>
>>>> No. Besides the syntactic reality that it wouldn't work, it would also
>>>> break various code because you then have to resolve the ambiguity between
>>>> initializer_list constructors and non-initializer_list constructors.
>>>>
>>>
>>> The model with ~{items} shown above seems to be pretty unambiguous.
>>>
>>
>> First, the proposal has {l:}, which can have those semantics in template
>> deduction situations.
>>
>
> Can {l:items} be forwarded?
>
What do you mean by "forwarded"? It's an initializer_list. If {l:} is not
used in aggregate initialization, then we could have it build an
initializer_list when used in template deduction scenarios. And you can't
use initializer_lists to initialize an aggregate.
> If not, then ~{items} with ()-wise initialization syntax solves more
> issues than {l:items}:
> 1) disambiguation between arguments for constructor and elements of a
> tuple-like entity;
> 2) forwarding.
>
>
>> More importantly, that doesn't solve the problem, because you don't
>> provide a mechanism equivalent to {c:}.
>>
>
> I'm not even sure what exactly {c:} is supposed to do.
>
> struct X
> {
> X(int);
> X(std::initializer_list<int>);
> };
>
> void f()
> {
> X x1{c: std::initializer_list<int>{20}}; // ?
> X x2{c: {20}}; // ?
> X x3{c: {c: 20}}; // ?
> }
>
> What should happen in these cases?
>
x1 will do exactly what it says. Since the members of {c:} match a
constructor exactly, it will call that constructor. That the parameter to
this constructor just so happens to be of type `std::initializer_list` is
irrelevant. This works exactly as it would if you used
{std::initializer_list<int>{20}} with the current syntax. This is defined
per the rules of 13.3.1.7, just as if you'd passed an initializer_list as
an argument to the constructor.
Remember: the 13.3.1.7 provisions about std::initializer_list constructors
are about considering the members of the braced-init-list to be the *members
* of an initailizer_list. That one of the members might itself be an
initializer_list is irrelevant to that point.
x2 would follow the current overload rules. {20} could be used to
initialize both `int` and `std::initializer_list<int>` equally. I'm fairly
sure this would be considered an ambiguous call, since both conversions are
equally good. If int{20} is not considered a conversion, then it may pick
the `int` constructor, as it is an exact match. But I'd have to look at
13.3.3.1 and 2 in more detail to know for sure. More importantly, the
behavior will be consistent with how {{20}} currently behaves.
x3 is also very clear. A `std::initializer_list<int>` has no constructor
that takes a single integer, so an implicit conversion from {c:20} to that
is not possible. Therefore, it will call the `int` constructor of `X`.
Should {c: items} prevent narrowing conversions?
>
void g(int n)
> {
> double d1{n}; // ill-formed according to the C++11 rules
> double d2{c: n}; // is this well-formed or not?
> }
>
I'll pretend that `n` is a double and `d1` and `d2` are ints, because
otherwise there's no narrowing (int to double is not narrowing). And yes,
per the uniform initialization rules, narrowing would be forbidden.
You keep missing the simplicity of the proposal: the *only thing* that
changes is which constructors get enumerated by 13.3.1.7's overloading
rules and in what order. Nothing else about uniform initialization is
affected.
>
> Or to {cl:}, which is also desirable.
>>
>
> For what purposes?
>
>
>> Do you see the difference between the behavior of a tool and goals of a
>>> programmer?
>>>
>>
>> I don't see what you're getting at here.
>>
>
> That explains the strange wishes.
>
> The whole point of adding language features is to provide mechanisms for
>> programmers to more directly express their intents and desires.
>>
>
> How exactly would {cl:} and {lc:} help to express intents and desires more
> directly?
>
Because that's what some people want. Some people want these to work the
same:
std::vector<int> v = {20, 30, 40, 50};
std::vector<std::vector<int>> vv;
vv.emplace_back(20, 30, 40, 50);
For some people, that's a reasonable thing to want to be the same. If they
pass a bunch of values, then they should be able to be formed into an
initializer_list constructor. That is, "emplace_back" should use every tool
available to actually construct the object from the parameters it is given.
It is not my place to second-guess the desires of a programmer. It's my
place to allow them to effectively express those desires to the compiler.
We don't have ways to control how an object gets used externally in any
>>>> other way.
>>>>
>>>
>>> std::make_shared and emplace_back just don't need to know that.
>>>
>>
>> But that's what you asked for: "user of the library component to decide
>> how exactly the initialization shall be done" That's external (ie: not
>> defined within the function) control over how an object gets used. So do
>> you want external control over how a template type is initialized (ie:
>> used) or do you not?
>>
>
> I was talking about internal control (within the template definition) over
> an external usage (on the user side).
>
>
>> Usually requirements imposed on template arguments are not arbitrary,
>>> they reflect (ideally minimal) conditions under which the desirable
>>> semantics can be implemented. Could you provide an example of an underlying
>>> task for which "I expect to be able to call {lc: ...} to initialize the
>>> type you pass for some set of values" would be a reasonable condition?
>>>
>>
>> emplace. make_shared. make_unique. Indeed, *any* function that forwards
>> parameters for initialization purposes specifies as part of its concept how
>> it wants to initialize the type. A good initialization forwarding function
>> would use either {c:} (to force you to always use initializer_lists
>> explicitly) or {cl:}, so that you could use aggregates with them.
>>
>
> There can exist a superior approach for forwarding:
>
> struct Aggregate { int x, y; };
>
> void f()
> {
> auto p1 = make_unique<Aggregate>(~{2, 1});
> // aggregate initialization: new Aggregate(~{2, 1})
>
> auto p2 = make_unique<std::vector<int>>(2, 1);
> // initialization by the non-initializer-list constructor: new
> std::vector<int>(2, 1)
>
> auto p3 = make_unique<std::vector<int>>(~{2, 1});
> // initialization by the initializer-list constructor: new
> std::vector<int>(~{2, 1})
> }
>
You seem to have missed the non-uniformity:
struct Type { int x, y; Type(int _x, int _y) : x(_x), y(_y) };
auto p4 = make_unique<Type>(2, 1);
// initialization by the constructor.
auto p5 = make_unqiue<Type>(~{2, 1});
// Compiler error; cannot initialize from an initializer_list constructor.
Why should `Type` be initialized via direct constructor initialization,
while `Aggregate` has to use your `~{}` syntax? That's not uniform, and
therefore works against *the whole point* of uniform initialization. I, as
the user, should neither know nor care if `Aggregate` or `Type` has a
constructor or is an aggregate. I simply want to pass these two parameters
to it to initialize it. So do that.
Also, your code doesn't allow aggregate initialization in cases where
`Aggregate` isn't just a bunch of `ints`. You know, if it has multiple
types. Indeed, I don't see how p1 works at all, considering that you cannot
initialize an aggregate from an initializer_list.
Also, forwarding is not an initialization problem; it's a separate issue.
You cannot forward the mechanics of braced-init-lists, because
braced-init-lists are not expressions or values. If you let someone else
initialize your objects for you, then *they* will decide on the semantics
of that initialization, not you. All you can provide are parameters.
My goal is to better allow the function actually doing the initialization
to express their intent. Whether someone can forward their intent to
another function is an orthogonal issue.
> Are there any other tasks for which {lc: ...} would be useful?
>
I don't second-guess Bjarne Stroustrup. {lc:} is the current behavior, and
he clearly thought it was reasonable for some reason. Therefore, unless you
can prove that it is of no value to the user, I will operate under the
assumption that he knows what he's talking about.
Personally, I don't much care for it; as I said in the proposal, I would
have preferred if you were forced to add the extra {} if you wanted
initializer_list initialization. I'm simply making the feature better in
whatever way I can, not throwing it away and creating something new.
--
------=_Part_332_452707.1357507839713
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Sunday, January 6, 2013 12:03:34 PM UTC-8, Nikolay Ivchenkov wro=
te:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;">On Sunday, January 6, 2013 =
3:02:01 AM UTC+4, Nicol Bolas wrote:<blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div>Again, you seem to be ignoring the reasons why we <i>want</i> uniform=
initialization syntax.<br></div></blockquote><div><br>I prefer to compare =
different approaches, rather than to concentrate on a single approach exclu=
sively as if it would be the only possible solution.<br></div></blockquote>=
<div><br>That's wonderful; do it <i>elsewhere</i>. Please stop derailing th=
is thread with counterproposals; I'm trying to refine <i>this</i> proposal =
into something that improves uniform initialization. Stop turning this into=
a "here's a completely different initialization syntax that has completely=
different semantics that are in no way shape or form uniform that we shoul=
d adopt instead" thread.<br> <br></div><blockquote class=3D"gmail_quot=
e" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddin=
g-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-le=
ft:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class=3D"=
gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid=
;padding-left:1ex"><blockquote class=3D"gmail_quote" style=3D"margin:0;marg=
in-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote clas=
s=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc =
solid;padding-left:1ex"><div>Note that function templates like emplace_back=
would immediately get an ability to perform an aggregate initialization an=
d forward initializer lists to initializer-list constructors, while library=
implementors, that currently use ()-wise initialization, would not need to=
change anything in their code for that. This would actually imply that ()-=
wise initialization would be a functionally uniform initialization with a s=
ingle consistent semantics (as opposed to visually uniform {}-wise initiali=
zation with irregular dual semantics). Isn't this a superior alternative fo=
r your proposal?<br></div></blockquote><div><br>No. Besides the syntactic r=
eality that it wouldn't work, it would also break various code because you =
then have to resolve the ambiguity between initializer_list constructors an=
d non-initializer_list constructors.</div></blockquote><div><br>The model w=
ith ~{items} shown above seems to be pretty unambiguous.<br></div></blockqu=
ote><div><br>First, the proposal has {l:}, which can have those semantics i=
n template deduction situations.</div></blockquote><div><br>Can {l:items} b=
e forwarded?</div></blockquote><div><br>What do you mean by "forwarded"? It=
's an initializer_list. If {l:} is not used in aggregate initialization, th=
en we could have it build an initializer_list when used in template deducti=
on scenarios. And you can't use initializer_lists to initialize an aggregat=
e.<br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;marg=
in-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>If not,=
then ~{items} with ()-wise initialization syntax solves more issues than {=
l:items}:<br>1) disambiguation between arguments for constructor and elemen=
ts of a tuple-like entity;<br>2) forwarding.<br> </div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc=
solid;padding-left:1ex"><div> More importantly, that doesn't solve the pro=
blem, because you don't provide a mechanism equivalent to {c:}.</div></bloc=
kquote><div><br>I'm not even sure what exactly {c:} is supposed to do.<br><=
br> struct X<br> {<br>  =
; X(int);<br> &n=
bsp; X(std::initializer_list<int>);<br> };<br><br>&=
nbsp; void f()<br> {<br> &nb=
sp; X x1{c: std::initializer_list<int>{20}<wbr>}; /=
/ ?<br> X x2{c: {20}}; // ?<br>&n=
bsp; X x3{c: {c: 20}}; // ?<br> &n=
bsp; }<br><br>What should happen in these cases?</div></blockquote><d=
iv><br>x1 will do exactly what it says. Since the members of {c:} match a c=
onstructor exactly, it will call that constructor. That the parameter to th=
is constructor just so happens to be of type `std::initializer_list` is irr=
elevant. This works exactly as it would if you used {std::initializer_list&=
lt;int>{20}} with the current syntax. This is defined per the rules of 1=
3.3.1.7, just as if you'd passed an initializer_list as an argument to the =
constructor.<br><br>Remember: the 13.3.1.7 provisions about std::initialize=
r_list constructors are about considering the members of the braced-init-li=
st to be the <i>members</i> of an initailizer_list. That one of the members=
might itself be an initializer_list is irrelevant to that point.<br><br>x2=
would follow the current overload rules. {20} could be used to initialize =
both `int` and `std::initializer_list<int>` equally. I'm fairly sure =
this would be considered an ambiguous call, since both conversions are equa=
lly good. If int{20} is not considered a conversion, then it may pick the `=
int` constructor, as it is an exact match. But I'd have to look at 13.3.3.1=
and 2 in more detail to know for sure. More importantly, the behavior will=
be consistent with how {{20}} currently behaves.<br><div><wbr></div>x3 is =
also very clear. A `std::initializer_list<int>` has no constructor th=
at takes a single integer, so an implicit conversion from {c:20} to that is=
not possible. Therefore, it will call the `int` constructor of `X`.<br><br=
></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.=
8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div> Should {c: items}=
prevent narrowing conversions? <br></div></blockquote><blockquote class=3D=
"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc s=
olid;padding-left: 1ex;"><div> void g(int n)<br> &nb=
sp; {<br> double d1{n}; // =
ill-formed according to the C++11 rules<br> =
double d2{c: n}; // is this well-formed or not?<br> }<br=
></div></blockquote><div><br>I'll pretend that `n` is a double and `d1` and=
`d2` are ints, because otherwise there's no narrowing (int to double is no=
t narrowing). And yes, per the uniform initialization rules, narrowing woul=
d be forbidden.<br><br>You keep missing the simplicity of the proposal: the=
<i>only thing</i> that changes is which constructors get enumerated by 13.=
3.1.7's overloading rules and in what order. Nothing else about uniform ini=
tialization is affected.<br> </div><blockquote class=3D"gmail_quote" s=
tyle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-le=
ft: 1ex;"><div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:=
0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div> Or t=
o {cl:}, which is also desirable.<br></div></blockquote><div><br>For what p=
urposes?<br> </div><blockquote class=3D"gmail_quote" style=3D"margin:0=
;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote=
class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px =
#ccc solid;padding-left:1ex"><div>Do you see the difference between the beh=
avior of a tool and goals of a programmer?<br></div></blockquote><div><br>I=
don't see what you're getting at here.<br></div></blockquote><div><br>That=
explains the strange wishes.<br><br><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex=
"><div> The whole point of adding language features is to provide mechanism=
s for
programmers to more directly express their intents and desires.</div></blo=
ckquote><br>How exactly would {cl:} and {lc:} help to express intents and d=
esires more directly?<br></div></blockquote><div><br>Because that's what so=
me people want. Some people want these to work the same:<br><br><div class=
=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border-colo=
r: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wrap: b=
reak-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span=
style=3D"color: #000;" class=3D"styled-by-prettify">std</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">vector</span><span style=3D"color: #=
080;" class=3D"styled-by-prettify"><int></span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> v </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">{</span><span style=3D"color: #066;" class=3D"styled-by-pret=
tify">20</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an style=3D"color: #066;" class=3D"styled-by-prettify">30</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066;" =
class=3D"styled-by-prettify">40</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettif=
y">50</span><span style=3D"color: #660;" class=3D"styled-by-prettify">};</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>std</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify">vector</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify">std</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify">vector</span><span style=3D"color: #080;" class=
=3D"styled-by-prettify"><int></span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">></span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> vv</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br>vv</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify">emplace_ba=
ck</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span>=
<span style=3D"color: #066;" class=3D"styled-by-prettify">20</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066=
;" class=3D"styled-by-prettify">30</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-pret=
tify">40</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an style=3D"color: #066;" class=3D"styled-by-prettify">50</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"><br></span></div></code></div><br>Fo=
r some people, that's a reasonable thing to want to be the same. If they pa=
ss a bunch of values, then they should be able to be formed into an initial=
izer_list constructor. That is, "emplace_back" should use every tool availa=
ble to actually construct the object from the parameters it is given.<br><b=
r>It is not my place to second-guess the desires of a programmer. It's my p=
lace to allow them to effectively express those desires to the compiler.<br=
><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left=
: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><blockquote class=3D"gmail_quote" style=3D"margin:0;=
margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote =
class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #=
ccc solid;padding-left:1ex"><div>We don't have ways to control how an objec=
t gets used externally in any other way.</div></blockquote><div><br>std::ma=
ke_shared and emplace_back just don't need to know that.<br></div></blockqu=
ote><div><br>But that's what you asked for: "user of the library component =
to decide how=20
exactly the initialization shall be done" That's external (ie: not defined =
within the function) control over how an object gets used. So do you want e=
xternal control over how a template type is initialized (ie: used) or do yo=
u not?<br></div></blockquote><div><br>I was talking about internal control =
(within the template definition) over an external usage (on the user side).=
<br> </div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-=
left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div> </div><blockq=
uote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:=
1px #ccc solid;padding-left:1ex"><div>Usually requirements imposed on templ=
ate arguments are not arbitrary, they reflect (ideally minimal) conditions =
under which the desirable semantics can be implemented. Could you provide a=
n example of an underlying task for which "I expect to be able to call {lc:=
...} to initialize the type you pass for some set of values" would be a re=
asonable condition?<br></div></blockquote><div><br>emplace. make_shared. ma=
ke_unique. Indeed, <i>any</i> function that forwards parameters for initial=
ization purposes specifies as part of its concept how it wants to initializ=
e the type. A good initialization forwarding function would use either {c:}=
(to force you to always use initializer_lists explicitly) or {cl:}, so tha=
t you could use aggregates with them.<br></div></blockquote><div><br>There =
can exist a superior approach for forwarding:<br><br> str=
uct Aggregate { int x, y; };<br><br> void f()<br> &n=
bsp; {<br> auto p1 =3D make=
_unique<Aggregate>(~{2, 1});<br> &=
nbsp; // aggregate initialization: new Aggregate(~{2, 1})<br><br> &nbs=
p; auto p2 =3D make_unique<std::vector<=
int>>(<wbr>2, 1);<br> // in=
itialization by the non-initializer-list constructor: new std::vector<in=
t>(2, 1) <br></div></blockquote><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;"><div><br> auto p3 =3D make_=
unique<std::vector<int>>(<wbr>~{2, 1});<br> &n=
bsp; // initialization by the initializer-list constructo=
r: new std::vector<int>(~{2, 1})<br> }<br></div></b=
lockquote><div><br>You seem to have missed the non-uniformity:<br><br></div=
><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); =
border-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; w=
ord-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyp=
rint"><span style=3D"color: #008;" class=3D"styled-by-prettify">struct</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #606;" class=3D"styled-by-prettify">Type</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"=
styled-by-prettify">int</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> x</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> y</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #606;" class=3D"styled-by-prettify">Type</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #008=
;" class=3D"styled-by-prettify">int</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> _x</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">=
int</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> _y</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">:</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> x</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify">_x</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">),</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> y</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify">_y</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">};</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br><br></span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> p4 </span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> make_unique</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify"><</span><span style=3D"color: #606;" class=3D"styled-by-prettify"=
>Type</span><span style=3D"color: #660;" class=3D"styled-by-prettify">>(=
</span><span style=3D"color: #066;" class=3D"styled-by-prettify">2</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #066;" class=3D"styled-by-prettify">1</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"><br></span><span style=3D"color: #800;" class=3D"style=
d-by-prettify">// initialization by the constructor.</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br><br></span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> p5 </span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> make_unqiue</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify"><</span><span style=3D"color: #606;" class=3D"st=
yled-by-prettify">Type</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">>(~{</span><span style=3D"color: #066;" class=3D"styled-by-p=
rettify">2</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><=
span style=3D"color: #066;" class=3D"styled-by-prettify">1</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">});</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #=
800;" class=3D"styled-by-prettify">// Compiler error; cannot initialize fro=
m an initializer_list constructor.</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br></span></div></code></div><div><br>Why should `=
Type` be initialized via direct constructor initialization, while `Aggregat=
e` has to use your `~{}` syntax? That's not uniform, and therefore works ag=
ainst <i>the whole point</i> of uniform initialization. I, as the user, sho=
uld neither know nor care if `Aggregate` or `Type` has a constructor or is =
an aggregate. I simply want to pass these two parameters to it to initializ=
e it. So do that.<br><br>Also, your code doesn't allow aggregate initializa=
tion in cases where `Aggregate` isn't just a bunch of `ints`. You know, if =
it has multiple types. Indeed, I don't see how p1 works at all, considering=
that you cannot initialize an aggregate from an initializer_list.<br><br>A=
lso, forwarding is not an initialization problem; it's a separate issue. Yo=
u cannot forward the mechanics of braced-init-lists, because braced-init-li=
sts are not expressions or values. If you let someone else initialize your =
objects for you, then <i>they</i> will decide on the semantics of that init=
ialization, not you. All you can provide are parameters.<br><br>My goal is =
to better allow the function actually doing the initialization to express t=
heir intent. Whether someone can forward their intent to another function i=
s an orthogonal issue.<br><br></div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;"><div> <br>Are there any other tasks for which {lc: ...} would be=
useful?</div></blockquote><div><br>I don't second-guess Bjarne Stroustrup.=
{lc:} is the current behavior, and he clearly thought it was reasonable fo=
r some reason. Therefore, unless you can prove that it is of no value to th=
e user, I will operate under the assumption that he knows what he's talking=
about.<br><br>Personally, I don't much care for it; as I said in the propo=
sal, I would have preferred if you were forced to add the extra {} if you w=
anted initializer_list initialization. I'm simply making the feature better=
in whatever way I can, not throwing it away and creating something new.<br=
></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_332_452707.1357507839713--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Mon, 7 Jan 2013 01:07:29 -0800 (PST)
Raw View
------=_Part_1315_15477039.1357549649260
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Monday, January 7, 2013 1:30:39 AM UTC+4, Nicol Bolas wrote:
>
> On Sunday, January 6, 2013 12:03:34 PM UTC-8, Nikolay Ivchenkov wrote:
>>
>>
>> I prefer to compare different approaches, rather than to concentrate on =
a=20
>> single approach exclusively as if it would be the only possible solution=
..
>>
>
> That's wonderful; do it *elsewhere*.
>
I could write an alternative proposal, but it's not likely that it would be=
=20
approved. As well as yours.
=20
> Can {l:items} be forwarded?
>>
>
> What do you mean by "forwarded"?
>
I mean the ability to write a function template f, that creates an object x=
=20
of type T so that for every well-defined {l:items} or for the vast majority=
=20
of such constructs the call f<T>({l:items}) would perform initialization of=
=20
x in the same way as the variable definition of the form T x({l:items}).
=20
> Should {c: items} prevent narrowing conversions?=20
>>
> void g(int n)
>> {
>> double d1{n}; // ill-formed according to the C++11 rules
>> double d2{c: n}; // is this well-formed or not?
>> }
>>
>
> I'll pretend that `n` is a double and `d1` and `d2` are ints, because=20
> otherwise there's no narrowing (int to double is not narrowing).
>
See 8.5.4/7/3:
A narrowing conversion is an implicit conversion
[...]
=97 from an integer type or unscoped enumeration type to a=20
floating-point type, except where the source is a constant expression and=
=20
the actual value after conversion will fit into the target type and will=20
produce the original value when converted back to the original type
In the example n is not a constant expression, so the definition
double d1{n};
invokes a narrowing conversion.
And yes, per the uniform initialization rules, narrowing would be forbidden=
..
>
> You keep missing the simplicity of the proposal: the *only thing* that=20
> changes is which constructors get enumerated by 13.3.1.7's overloading=20
> rules and in what order. Nothing else about uniform initialization is=20
> affected.
>
You are suggesting to make a breaking change then: if emplace_back would=
=20
use your syntax, then the following code would not be valid anymore.
std::vector<double> v;
v.emplace_back(0); // error: narrowing conversion from int to double
=20
> How exactly would {cl:} and {lc:} help to express intents and desires mor=
e=20
>> directly?
>>
>
> Because that's what some people want. Some people want these to work the=
=20
> same:
>
> std::vector<int> v =3D {20, 30, 40, 50};
> std::vector<std::vector<int>> vv;
> vv.emplace_back(20, 30, 40, 50);
>
=20
Sometimes people want strange things. There should be an objective reason=
=20
to do so. From my point of view, vv.emplace_back(20, 30, 40, 50) is much=20
less informative (for people who will read the code) than vv.emplace_back(~
{20, 30, 40, 50}).
For some people, that's a reasonable thing to want to be the same. If they=
=20
> pass a bunch of values, then they should be able to be formed into an=20
> initializer_list constructor. That is, "emplace_back" should use every to=
ol=20
> available to actually construct the object from the parameters it is give=
n.
>
And readers have to spend a lot of time in order to find out what such a=20
code is supposed to do. Moreover, if we have something like this
struct X
{
X(int);
X(std::initializer_list<int>);
};
we can't later add a constructor with additional parameter of type int
X(int, int);
so that this change would not imply potential breakage of a client's code.
It is not my place to second-guess the desires of a programmer. It's my=20
> place to allow them to effectively express those desires to the compiler.
>
You will change your opinion when you will have to debug or modify such a=
=20
code.
=20
> You seem to have missed the non-uniformity:
>
> struct Type { int x, y; Type(int _x, int _y) : x(_x), y(_y) };
>
> auto p4 =3D make_unique<Type>(2, 1);
> // initialization by the constructor.
>
> auto p5 =3D make_unqiue<Type>(~{2, 1});
> // Compiler error; cannot initialize from an initializer_list constructor=
..
>
> Why should `Type` be initialized via direct constructor initialization,=
=20
> while `Aggregate` has to use your `~{}` syntax?
>
That's because an aggregate (as well as a container like std::vector<int>)=
=20
can always be considered as a sequence of items (which can be initialized=
=20
by the respective items of an initializer-list), while a constructor with=
=20
two parameters doesn't necessarily perform an itemwise initialization of=20
some sequence. If we want to support an itemwise initialization, we could=
=20
express this intent explicitly by defining a special constructor:
struct Type
{
int x, y;
Type(int _x, int _y) : // (1)
Type(~{_x, _y}) {}
Type(std::braced_init_list<int const &, int const &> &&li) : // (2)
_x(li.get<0>()), _y(li.get<1>()) {}
};
auto p =3D make_unqiue<Type>(~{2, 1}); // OK: calls (2)
=20
> That's not uniform
>
That's intentionally non-uniform.
=20
> and therefore works against *the whole point* of uniform initialization.
>
against the whole point which is purely abstract :-)
=20
> I, as the user, should neither know nor care if `Aggregate` or `Type` has=
=20
> a constructor or is an aggregate.
>
....unless you do care about programmers who will try to understand your=20
code.
=20
> Also, your code doesn't allow aggregate initialization in cases where=20
> `Aggregate` isn't just a bunch of `ints`.
>
~{items} is supposed to reflect types and value categories of all its items=
=20
and cover nesting:
~{ ~{"text", nullptr}, 1 }
and
~{ {"text", nullptr}, 1 }
would have the type std::braced_init_list<std::braced_init_list<const char=
=20
(&)[5], std::nullptr_t>, int>
=20
> Also, forwarding is not an initialization problem; it's a separate issue.=
=20
> You cannot forward the mechanics of braced-init-lists, because=20
> braced-init-lists are not expressions or values.
>
And I don't want to forward the mechanics of braced-init-lists, because=20
it's too complicated and irregular. It would be enough to be able to=20
initialize aggregates and objects of types std::initializer_list<ItemType>=
=20
or std::braced_init_list<ItemTypes...> from forwarded lists.=20
Are there any other tasks for which {lc: ...} would be useful?
>>
>
I was going to ask about {cl: ...}, but I made a typo :-)
=20
> I don't second-guess Bjarne Stroustrup. {lc:} is the current behavior, an=
d=20
> he clearly thought it was reasonable for some reason.
>
I have a simple explanation of that current behavior: the items of the=20
paragraph 8.5.4/3 are ordered in a way that for every particular case of=20
application of list-initialization give us the behavior which would be the=
=20
most likely expected (in opinion of the authors of the rules) among=20
possible alternatives. In spite of that, list-initialization (being used=20
solely) does not give us an ability to express every desirable way of=20
initialization and often we get an unexpected behavior. We have to use this=
=20
obscenity sometimes only because the language does not provide any=20
alternative ways to get a desirable behavior using a less obscure notation.
--=20
------=_Part_1315_15477039.1357549649260
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Monday, January 7, 2013 1:30:39 AM UTC+4, Nicol Bolas wrote:<blockquote =
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1p=
x #ccc solid;padding-left: 1ex;">On Sunday, January 6, 2013 12:03:34 PM UTC=
-8, Nikolay Ivchenkov wrote:<blockquote class=3D"gmail_quote" style=3D"marg=
in:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div><b=
r>I prefer to compare different approaches, rather than to concentrate on a=
single approach exclusively as if it would be the only possible solution.<=
br></div></blockquote><div><br>That's wonderful; do it <i>elsewhere</i>.</d=
iv></blockquote><div><br>I could write an alternative proposal, but it's no=
t likely that it would be approved. As well as yours.<br> </div><block=
quote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-le=
ft: 1px #ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1=
ex"><div>Can {l:items} be forwarded?</div></blockquote><div><br>What do you=
mean by "forwarded"?</div></blockquote><div><br>I mean the ability to writ=
e a function template f, that creates an object x of type T so that for eve=
ry well-defined {l:items} or for the vast majority of such constructs the c=
all f<T>({l:items}) would perform initialization of x in the same way=
as the variable definition of the form T x({l:items}).<br> </div><blo=
ckquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-=
left: 1px #ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" =
style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left=
:1ex"><div> Should {c: items} prevent narrowing conversions? <br></div></bl=
ockquote><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.=
8ex;border-left:1px #ccc solid;padding-left:1ex"><div> vo=
id g(int n)<br> {<br> =
double d1{n}; // ill-formed according to the C++11 rules<br> &=
nbsp; double d2{c: n}; // is this well-formed or not?<br=
> }<br></div></blockquote><div><br>I'll pretend that `n` =
is a double and `d1` and `d2` are ints, because otherwise there's no narrow=
ing (int to double is not narrowing).</div></blockquote><div><br>See 8.5.4/=
7/3:<br><br> A narrowing conversion is an implicit conver=
sion<br> [...]<br> &nb=
sp; =97 from an integer type or unscoped enumeratio=
n type to a floating-point type, except where the source is a constant expr=
ession and the actual value after conversion will fit into the target type =
and will produce the original value when converted back to the original typ=
e<br><br>In the example n is not a constant expression, so the definition<b=
r><br> double d1{n};<br><br>invokes a narrowing conversio=
n.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin=
-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div> And yes,=
per the uniform initialization rules, narrowing would be forbidden.<br><br=
>You keep missing the simplicity of the proposal: the <i>only thing</i> tha=
t changes is which constructors get enumerated by 13.3.1.7's overloading ru=
les and in what order. Nothing else about uniform initialization is affecte=
d.<br></div></blockquote><div><br> You are suggesting to make a breaki=
ng change then: if emplace_back would use your syntax, then the following c=
ode would not be valid anymore.<br><br> std::vector<do=
uble> v;<br> v.emplace_back(0); // error: narrowing co=
nversion from int to double<br> </div><blockquote class=3D"gmail_quote=
" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding=
-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-lef=
t:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div></div><div>How ex=
actly would {cl:} and {lc:} help to express intents and desires more direct=
ly?<br></div></blockquote><div><br>Because that's what some people want. So=
me people want these to work the same:<br><br><div style=3D"background-colo=
r:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-=
width:1px;word-wrap:break-word"><code><div><span style=3D"color:#000">std</=
span><span style=3D"color:#660">::</span><span style=3D"color:#000">vector<=
/span><span style=3D"color:#080"><int></span><span style=3D"color:#00=
0"> v </span><span style=3D"color:#660">=3D</span><span style=3D"color:#000=
"> </span><span style=3D"color:#660">{</span><span style=3D"color:#066">20<=
/span><span style=3D"color:#660">,</span><span style=3D"color:#000"> </span=
><span style=3D"color:#066">30</span><span style=3D"color:#660">,</span><sp=
an style=3D"color:#000"> </span><span style=3D"color:#066">40</span><span s=
tyle=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=
=3D"color:#066">50</span><span style=3D"color:#660">};</span><span style=3D=
"color:#000"><br>std</span><span style=3D"color:#660">::</span><span style=
=3D"color:#000">vector</span><span style=3D"color:#660"><</span><span st=
yle=3D"color:#000">std</span><span style=3D"color:#660">::</span><span styl=
e=3D"color:#000">vector</span><span style=3D"color:#080"><int></span>=
<span style=3D"color:#660">></span><span style=3D"color:#000"> vv</span>=
<span style=3D"color:#660">;</span><span style=3D"color:#000"><br>vv</span>=
<span style=3D"color:#660">.</span><span style=3D"color:#000">emplace_back<=
/span><span style=3D"color:#660">(</span><span style=3D"color:#066">20</spa=
n><span style=3D"color:#660">,</span><span style=3D"color:#000"> </span><sp=
an style=3D"color:#066">30</span><span style=3D"color:#660">,</span><span s=
tyle=3D"color:#000"> </span><span style=3D"color:#066">40</span><span style=
=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=3D"c=
olor:#066">50</span><span style=3D"color:#660">);</span><span style=3D"colo=
r:#000"><br></span></div></code></div></div></blockquote><div> <br>Som=
etimes people want strange things. There should be an objective reason to d=
o so. From my point of view, <code><span style=3D"color:#000">vv</span><spa=
n style=3D"color:#660">.</span><span style=3D"color:#000">emplace_back</spa=
n><span style=3D"color:#660">(</span><span style=3D"color:#066">20</span><s=
pan style=3D"color:#660">,</span><span style=3D"color:#000"> </span><span s=
tyle=3D"color:#066">30</span><span style=3D"color:#660">,</span><span style=
=3D"color:#000"> </span><span style=3D"color:#066">40</span><span style=3D"=
color:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color=
:#066">50</span><span style=3D"color:#660">)</span></code> is much less inf=
ormative (for people who will read the code) than <code><span style=3D"colo=
r:#000">vv</span><span style=3D"color:#660">.</span><span style=3D"color:#0=
00">emplace_back</span><span style=3D"color:#660">(~</span><span style=3D"c=
olor:#066">{20</span><span style=3D"color:#660">,</span><span style=3D"colo=
r:#000"> </span><span style=3D"color:#066">30</span><span style=3D"color:#6=
60">,</span><span style=3D"color:#000"> </span><span style=3D"color:#066">4=
0</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> </sp=
an><span style=3D"color:#066">50}</span><span style=3D"color:#660">).</span=
></code><br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;=
margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>For=
some people, that's a reasonable thing to want to be the same. If they pas=
s a bunch of values, then they should be able to be formed into an initiali=
zer_list constructor. That is, "emplace_back" should use every tool availab=
le to actually construct the object from the parameters it is given.<br></d=
iv></blockquote><div><br>And readers have to spend a lot of time in order t=
o find out what such a code is supposed to do. Moreover, if we have somethi=
ng like this<br><br> struct X<br> {<br>=
X(int);<br> &nb=
sp; X(std::initializer_list<int>);<br> &=
nbsp; };<br><br>we can't later add a constructor with additional parameter =
of type int<br><br> X(int, int);<br><br>so that this chan=
ge would not imply potential breakage of a client's code.<br><br></div><blo=
ckquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-=
left: 1px #ccc solid;padding-left: 1ex;"><div>It is not my place to second-=
guess the desires of a programmer. It's my place to allow them to effective=
ly express those desires to the compiler.<br></div></blockquote><div><br>Yo=
u will change your opinion when you will have to debug or modify such a cod=
e.<br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;marg=
in-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>You see=
m to have missed the non-uniformity:<br><br></div><div style=3D"background-=
color:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;bor=
der-width:1px;word-wrap:break-word"><code><div><span style=3D"color:#008">s=
truct</span><span style=3D"color:#000"> </span><span style=3D"color:#606">T=
ype</span><span style=3D"color:#000"> </span><span style=3D"color:#660">{</=
span><span style=3D"color:#000"> </span><span style=3D"color:#008">int</spa=
n><span style=3D"color:#000"> x</span><span style=3D"color:#660">,</span><s=
pan style=3D"color:#000"> y</span><span style=3D"color:#660">;</span><span =
style=3D"color:#000"> </span><span style=3D"color:#606">Type</span><span st=
yle=3D"color:#660">(</span><span style=3D"color:#008">int</span><span style=
=3D"color:#000"> _x</span><span style=3D"color:#660">,</span><span style=3D=
"color:#000"> </span><span style=3D"color:#008">int</span><span style=3D"co=
lor:#000"> _y</span><span style=3D"color:#660">)</span><span style=3D"color=
:#000"> </span><span style=3D"color:#660">:</span><span style=3D"color:#000=
"> x</span><span style=3D"color:#660">(</span><span style=3D"color:#000">_x=
</span><span style=3D"color:#660">),</span><span style=3D"color:#000"> y</s=
pan><span style=3D"color:#660">(</span><span style=3D"color:#000">_y</span>=
<span style=3D"color:#660">)</span><span style=3D"color:#000"> </span><span=
style=3D"color:#660">};</span><span style=3D"color:#000"><br><br></span><s=
pan style=3D"color:#008">auto</span><span style=3D"color:#000"> p4 </span><=
span style=3D"color:#660">=3D</span><span style=3D"color:#000"> make_unique=
</span><span style=3D"color:#660"><</span><span style=3D"color:#606">Typ=
e</span><span style=3D"color:#660">>(</span><span style=3D"color:#066">2=
</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> </spa=
n><span style=3D"color:#066">1</span><span style=3D"color:#660">);</span><s=
pan style=3D"color:#000"><br></span><span style=3D"color:#800">// initializ=
ation by the constructor.</span><span style=3D"color:#000"><br><br></span><=
span style=3D"color:#008">auto</span><span style=3D"color:#000"> p5 </span>=
<span style=3D"color:#660">=3D</span><span style=3D"color:#000"> make_unqiu=
e</span><span style=3D"color:#660"><</span><span style=3D"color:#606">Ty=
pe</span><span style=3D"color:#660">>(~{</span><span style=3D"color:#066=
">2</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> </=
span><span style=3D"color:#066">1</span><span style=3D"color:#660">});</spa=
n><span style=3D"color:#000"><br></span><span style=3D"color:#800">// Compi=
ler error; cannot initialize from an initializer_list constructor.</span><s=
pan style=3D"color:#000"><br></span></div></code></div><div><br>Why should =
`Type` be initialized via direct constructor initialization, while `Aggrega=
te` has to use your `~{}` syntax?</div></blockquote><div><br>That's because=
an aggregate (as well as a container like std::vector<int>) can alwa=
ys be considered as a sequence of items (which can be initialized by the re=
spective items of an initializer-list), while a constructor with two parame=
ters doesn't necessarily perform an itemwise initialization of some sequenc=
e. If we want to support an itemwise initialization, we could express this =
intent explicitly by defining a special constructor:<br><br> &nb=
sp; struct Type<br> {<br> &n=
bsp; int x, y;<br> Type(int=
_x, int _y) : // (1)<br> &n=
bsp; Type(~{_x, _y}) {}<br> =
Type(std::braced_init_list<int const &, int const &> &=
amp;&li) : // (2)<br> &n=
bsp; _x(li.get<0>()), _y(li.get<1>()) {}<br> &=
nbsp; };<br><br> auto p =3D make_unqiue<Type>=
(~{2, 1}); // OK: calls (2)<br> </div><blockquote class=3D"gmail_quote=
" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding=
-left: 1ex;"><div> That's not uniform</div></blockquote><div><br>That's int=
entionally non-uniform.<br> </div><blockquote class=3D"gmail_quote" st=
yle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-lef=
t: 1ex;"><div>and therefore works against <i>the whole point</i> of uniform=
initialization.</div></blockquote><div><br>against the whole point which i=
s purely abstract :-)<br> </div><blockquote class=3D"gmail_quote" styl=
e=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left:=
1ex;"><div> I, as the user, should neither know nor care if `Aggregate` or=
`Type` has a constructor or is an aggregate.</div></blockquote><div><br>..=
..unless you do care about programmers who will try to understand your code.=
<br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin=
-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div> Also, yo=
ur code doesn't allow aggregate initialization in cases where `Aggregate` i=
sn't just a bunch of `ints`.</div></blockquote><div><br>~{items} is suppose=
d to reflect types and value categories of all its items and cover nesting:=
<br><br> ~{ ~{"text", nullptr}, 1 }<br><br>and<br><br>&nb=
sp; ~{ {"text", nullptr}, 1 }<br><br>would have the type std::b=
raced_init_list<std::braced_init_list<const char (&)[5], std::nul=
lptr_t>, int><br> </div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;"><div>Also, forwarding is not an initialization problem; it's a separa=
te issue. You cannot forward the mechanics of braced-init-lists, because br=
aced-init-lists are not expressions or values.</div></blockquote><div><br>A=
nd I don't want to forward the mechanics of braced-init-lists, because it's=
too complicated and irregular. It would be enough to be able to initialize=
aggregates and objects of types std::initializer_list<ItemType> or s=
td::braced_init_list<ItemTypes...> from forwarded lists. <br><br></di=
v><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_q=
uote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;paddin=
g-left:1ex"><div> Are there any other tasks for which {lc: ...} would =
be useful?</div></blockquote></blockquote><div><br>I was going to ask about=
{cl: ...}, but I made a typo :-)<br> </div><blockquote class=3D"gmai=
l_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;=
padding-left: 1ex;"><div>I don't second-guess Bjarne Stroustrup. {lc:} is t=
he current behavior, and he clearly thought it was reasonable for some reas=
on.<br></div></blockquote><div><br>I have a simple explanation of that curr=
ent behavior: the items of the paragraph 8.5.4/3 are ordered in a way that =
for every particular case of application of list-initialization give us the=
behavior which would be the most likely expected (in opinion of the author=
s of the rules) among possible alternatives. In spite of that, list-initial=
ization (being used solely) does not give us an ability to express every de=
sirable way of initialization and often we get an unexpected behavior. We h=
ave to use this obscenity sometimes only because the language does not prov=
ide any alternative ways to get a desirable behavior using a less obscure n=
otation.</div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1315_15477039.1357549649260--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Mon, 7 Jan 2013 03:52:33 -0800 (PST)
Raw View
------=_Part_582_17079790.1357559553242
Content-Type: text/plain; charset=ISO-8859-1
On Monday, January 7, 2013 1:07:29 AM UTC-8, Nikolay Ivchenkov wrote:
>
> On Monday, January 7, 2013 1:30:39 AM UTC+4, Nicol Bolas wrote:
>>
>> On Sunday, January 6, 2013 12:03:34 PM UTC-8, Nikolay Ivchenkov wrote:
>>>
>>>
>>> I prefer to compare different approaches, rather than to concentrate on
>>> a single approach exclusively as if it would be the only possible solution.
>>>
>>
>> That's wonderful; do it *elsewhere*.
>>
>
> I could write an alternative proposal, but it's not likely that it would
> be approved. As well as yours.
>
We'll see about the latter; I very much intend to make it a formal
proposal, with a real number and everything. Though I can't attend a
meeting in the near future to properly defend it. As for the former, it
certainly won't be approved if you don't actually make a proposal. If you
think that it's something that should go into C++, that will make the
language better, then you should have a go at it.
Can {l:items} be forwarded?
>>>
>>
>> What do you mean by "forwarded"?
>>
>
> I mean the ability to write a function template f, that creates an object
> x of type T so that for every well-defined {l:items} or for the vast
> majority of such constructs the call f<T>({l:items}) would perform
> initialization of x in the same way as the variable definition of the form
> T x({l:items}).
>
There's no way to guarantee that. The best you can do is what I said: allow
{l:} to be template deduced as some form of std::initailizer_list of some
type, where possible. The problem is that you'd have to guess the type,
which can lead to mismatches when it comes time to use it with the actual
type. So it's not exactly "forwarding".
And yes, per the uniform initialization rules, narrowing would be forbidden.
>>
>> You keep missing the simplicity of the proposal: the *only thing* that
>> changes is which constructors get enumerated by 13.3.1.7's overloading
>> rules and in what order. Nothing else about uniform initialization is
>> affected.
>>
>
> You are suggesting to make a breaking change then: if emplace_back would
> use your syntax, then the following code would not be valid anymore.
>
> std::vector<double> v;
> v.emplace_back(0); // error: narrowing conversion from int to double
>
Fair enough. Though some might say that this is an improvement, that you *
should* be more explicit about the types of literals.
How exactly would {cl:} and {lc:} help to express intents and desires more
>>> directly?
>>>
>>
>> Because that's what some people want. Some people want these to work the
>> same:
>>
>> std::vector<int> v = {20, 30, 40, 50};
>> std::vector<std::vector<int>> vv;
>> vv.emplace_back(20, 30, 40, 50);
>>
>
> Sometimes people want strange things. There should be an objective reason
> to do so. From my point of view, vv.emplace_back(20, 30, 40, 50) is much
> less informative (for people who will read the code) than vv.emplace_back
> (~{20, 30, 40, 50}).
>
Yes, and some might say that memorizing different initialization rules for
different types of objects is a bad thing to. Some might say that having to
initialize types with constructors differently from those without is harder
to read too.
Some might say a lot of things. That doesn't make them right or not.
You asked how that would help express their intent. I explained how. The
fact that you don't like that reasoning doesn't make it any less valid to
those who do like it. Some people want to be able to do that, and I don't
believe there is a good reason to deny them.
You seem to have missed the non-uniformity:
>>
>> struct Type { int x, y; Type(int _x, int _y) : x(_x), y(_y) };
>>
>> auto p4 = make_unique<Type>(2, 1);
>> // initialization by the constructor.
>>
>> auto p5 = make_unqiue<Type>(~{2, 1});
>> // Compiler error; cannot initialize from an initializer_list constructor.
>>
>> Why should `Type` be initialized via direct constructor initialization,
>> while `Aggregate` has to use your `~{}` syntax?
>>
>
> That's because an aggregate (as well as a container like std::vector<int>)
> can always be considered as a sequence of items (which can be initialized
> by the respective items of an initializer-list),
>
No, it can't. It can only be initialized by an initializer_list if the
aggregate is a sequence of items of the *same* type. Remember:
std::initializer_list can only contain items of the same type.
while a constructor with two parameters doesn't necessarily perform an
> itemwise initialization of some sequence. If we want to support an itemwise
> initialization, we could express this intent explicitly by defining a
> special constructor:
>
> struct Type
> {
> int x, y;
> Type(int _x, int _y) : // (1)
> Type(~{_x, _y}) {}
> Type(std::braced_init_list<int const &, int const &> &&li) : // (2)
> _x(li.get<0>()), _y(li.get<1>()) {}
> };
>
> auto p = make_unqiue<Type>(~{2, 1}); // OK: calls (2)
>
>
>> That's not uniform
>>
>
> That's intentionally non-uniform.
>
Please read the thread title. It's called, "RFC: Towards More Uniform
Initialization Proposal". The thread is about a fix to uniform
initialization syntax to make it more uniform and more uniformly useable.
Your non-uniform commentary and suggestions are unhelpful. Please take your
discussion of non-uniform initialization syntax elsewhere. Your continued
thread derailment is starting to border on trolling at this point, since I
have *repeatedly* ask you to stop bringing these things up.
Are there any other tasks for which {lc: ...} would be useful?
>>>
>>
> I was going to ask about {cl: ...}, but I made a typo :-)
>
As I pointed out in the proposal, it's about orthogonality. You need {lc:}
because that's the default behavior, which can't be changed. Adding {cl:}
makes sense because it's expected given that you have {lc:}. It would seem
like a missing feature otherwise.
I don't second-guess Bjarne Stroustrup. {lc:} is the current behavior, and
>> he clearly thought it was reasonable for some reason.
>>
>
> I have a simple explanation of that current behavior: the items of the
> paragraph 8.5.4/3 are ordered in a way that for every particular case of
> application of list-initialization give us the behavior which would be the
> most likely expected (in opinion of the authors of the rules) among
> possible alternatives. In spite of that, list-initialization (being used
> solely) does not give us an ability to express every desirable way of
> initialization and often we get an unexpected behavior.
>
You're simply reiterating the purpose of this proposal: to fix the small
issues in what is otherwise a great initialization syntax, thus allowing
the user to express "every desirable way of initialization".
--
------=_Part_582_17079790.1357559553242
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Monday, January 7, 2013 1:07:29 AM UTC-8, Nikolay Ivchenkov wrot=
e:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;">On Monday, January 7, 2013 1=
:30:39 AM UTC+4, Nicol Bolas wrote:<blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
>On Sunday, January 6, 2013 12:03:34 PM UTC-8, Nikolay Ivchenkov wrote:<blo=
ckquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-le=
ft:1px #ccc solid;padding-left:1ex"><div><br>I prefer to compare different =
approaches, rather than to concentrate on a single approach exclusively as =
if it would be the only possible solution.<br></div></blockquote><div><br>T=
hat's wonderful; do it <i>elsewhere</i>.</div></blockquote><div><br>I could=
write an alternative proposal, but it's not likely that it would be approv=
ed. As well as yours.<br></div></blockquote><div><br>We'll see about the la=
tter; I very much intend to make it a formal proposal, with a real number a=
nd everything. Though I can't attend a meeting in the near future to proper=
ly defend it. As for the former, it certainly won't be approved if you don'=
t actually make a proposal. If you think that it's something that should go=
into C++, that will make the language better, then you should have a go at=
it.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;marg=
in-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><blockquote =
class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #=
ccc solid;padding-left:1ex"><blockquote class=3D"gmail_quote" style=3D"marg=
in:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>Ca=
n {l:items} be forwarded?</div></blockquote><div><br>What do you mean by "f=
orwarded"?</div></blockquote><div><br>I mean the ability to write a functio=
n template f, that creates an object x of type T so that for every well-def=
ined {l:items} or for the vast majority of such constructs the call f<T&=
gt;({l:items}) would perform initialization of x in the same way as the var=
iable definition of the form T x({l:items}).<br></div></blockquote><div><br=
>There's no way to guarantee that. The best you can do is what I said: allo=
w {l:} to be template deduced as some form of std::initailizer_list of some=
type, where possible. The problem is that you'd have to guess the type, wh=
ich can lead to mismatches when it comes time to use it with the actual typ=
e. So it's not exactly "forwarding".<br><br></div><blockquote class=3D"gmai=
l_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;=
padding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"margin:0;mar=
gin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div> And yes, =
per the uniform initialization rules, narrowing would be forbidden.<br><br>=
You keep missing the simplicity of the proposal: the <i>only thing</i> that=
changes is which constructors get enumerated by 13.3.1.7's overloading rul=
es and in what order. Nothing else about uniform initialization is affected=
..<br></div></blockquote><div><br> You are suggesting to make a breakin=
g change then: if emplace_back would use your syntax, then the following co=
de would not be valid anymore.<br><br> std::vector<dou=
ble> v;<br> v.emplace_back(0); // error: narrowing con=
version from int to double<br></div></blockquote><div><br>Fair enough. Thou=
gh some might say that this is an improvement, that you <i>should</i> be mo=
re explicit about the types of literals.<br><br></div><blockquote class=3D"=
gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc so=
lid;padding-left: 1ex;"><div></div><blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;bord=
er-left:1px #ccc solid;padding-left:1ex"><div></div><div>How exactly would =
{cl:} and {lc:} help to express intents and desires more directly?<br></div=
></blockquote><div><br>Because that's what some people want. Some people wa=
nt these to work the same:<br><br><div style=3D"background-color:rgb(250,25=
0,250);border-color:rgb(187,187,187);border-style:solid;border-width:1px;wo=
rd-wrap:break-word"><code><div><span style=3D"color:#000">std</span><span s=
tyle=3D"color:#660">::</span><span style=3D"color:#000">vector</span><span =
style=3D"color:#080"><int></span><span style=3D"color:#000"> v </span=
><span style=3D"color:#660">=3D</span><span style=3D"color:#000"> </span><s=
pan style=3D"color:#660">{</span><span style=3D"color:#066">20</span><span =
style=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=
=3D"color:#066">30</span><span style=3D"color:#660">,</span><span style=3D"=
color:#000"> </span><span style=3D"color:#066">40</span><span style=3D"colo=
r:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color:#06=
6">50</span><span style=3D"color:#660">};</span><span style=3D"color:#000">=
<br>std</span><span style=3D"color:#660">::</span><span style=3D"color:#000=
">vector</span><span style=3D"color:#660"><</span><span style=3D"color:#=
000">std</span><span style=3D"color:#660">::</span><span style=3D"color:#00=
0">vector</span><span style=3D"color:#080"><int></span><span style=3D=
"color:#660">></span><span style=3D"color:#000"> vv</span><span style=3D=
"color:#660">;</span><span style=3D"color:#000"><br>vv</span><span style=3D=
"color:#660">.</span><span style=3D"color:#000">emplace_back</span><span st=
yle=3D"color:#660">(</span><span style=3D"color:#066">20</span><span style=
=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=3D"c=
olor:#066">30</span><span style=3D"color:#660">,</span><span style=3D"color=
:#000"> </span><span style=3D"color:#066">40</span><span style=3D"color:#66=
0">,</span><span style=3D"color:#000"> </span><span style=3D"color:#066">50=
</span><span style=3D"color:#660">);</span><span style=3D"color:#000"><br><=
/span></div></code></div></div></blockquote><div> <br>Sometimes people=
want strange things. There should be an objective reason to do so. From my=
point of view, <code><span style=3D"color:#000">vv</span><span style=3D"co=
lor:#660">.</span><span style=3D"color:#000">emplace_back</span><span style=
=3D"color:#660">(</span><span style=3D"color:#066">20</span><span style=3D"=
color:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color=
:#066">30</span><span style=3D"color:#660">,</span><span style=3D"color:#00=
0"> </span><span style=3D"color:#066">40</span><span style=3D"color:#660">,=
</span><span style=3D"color:#000"> </span><span style=3D"color:#066">50</sp=
an><span style=3D"color:#660">)</span></code> is much less informative (for=
people who will read the code) than <code><span style=3D"color:#000">vv</s=
pan><span style=3D"color:#660">.</span><span style=3D"color:#000">emplace_b=
ack</span><span style=3D"color:#660">(~</span><span style=3D"color:#066">{2=
0</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> </sp=
an><span style=3D"color:#066">30</span><span style=3D"color:#660">,</span><=
span style=3D"color:#000"> </span><span style=3D"color:#066">40</span><span=
style=3D"color:#660">,</span><span style=3D"color:#000"> </span><span styl=
e=3D"color:#066">50}</span><span style=3D"color:#660">).</span></code><br><=
/div></blockquote><div><br>Yes, and some might say that memorizing differen=
t initialization rules for different types of objects is a bad thing to. So=
me might say that having to initialize types with constructors differently =
from those without is harder to read too.<br><br>Some might say a lot of th=
ings. That doesn't make them right or not.<br><br>You asked how that would =
help express their intent. I explained how. The fact that you don't like th=
at reasoning doesn't make it any less valid to those who do like it. Some p=
eople want to be able to do that, and I don't believe there is a good reaso=
n to deny them.<br><br></div><blockquote class=3D"gmail_quote" style=3D"mar=
gin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><=
div></div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0=
..8ex;border-left:1px #ccc solid;padding-left:1ex"><div>You seem to have mis=
sed the non-uniformity:<br><br></div><div style=3D"background-color:rgb(250=
,250,250);border-color:rgb(187,187,187);border-style:solid;border-width:1px=
;word-wrap:break-word"><code><div><span style=3D"color:#008">struct</span><=
span style=3D"color:#000"> </span><span style=3D"color:#606">Type</span><sp=
an style=3D"color:#000"> </span><span style=3D"color:#660">{</span><span st=
yle=3D"color:#000"> </span><span style=3D"color:#008">int</span><span style=
=3D"color:#000"> x</span><span style=3D"color:#660">,</span><span style=3D"=
color:#000"> y</span><span style=3D"color:#660">;</span><span style=3D"colo=
r:#000"> </span><span style=3D"color:#606">Type</span><span style=3D"color:=
#660">(</span><span style=3D"color:#008">int</span><span style=3D"color:#00=
0"> _x</span><span style=3D"color:#660">,</span><span style=3D"color:#000">=
</span><span style=3D"color:#008">int</span><span style=3D"color:#000"> _y=
</span><span style=3D"color:#660">)</span><span style=3D"color:#000"> </spa=
n><span style=3D"color:#660">:</span><span style=3D"color:#000"> x</span><s=
pan style=3D"color:#660">(</span><span style=3D"color:#000">_x</span><span =
style=3D"color:#660">),</span><span style=3D"color:#000"> y</span><span sty=
le=3D"color:#660">(</span><span style=3D"color:#000">_y</span><span style=
=3D"color:#660">)</span><span style=3D"color:#000"> </span><span style=3D"c=
olor:#660">};</span><span style=3D"color:#000"><br><br></span><span style=
=3D"color:#008">auto</span><span style=3D"color:#000"> p4 </span><span styl=
e=3D"color:#660">=3D</span><span style=3D"color:#000"> make_unique</span><s=
pan style=3D"color:#660"><</span><span style=3D"color:#606">Type</span><=
span style=3D"color:#660">>(</span><span style=3D"color:#066">2</span><s=
pan style=3D"color:#660">,</span><span style=3D"color:#000"> </span><span s=
tyle=3D"color:#066">1</span><span style=3D"color:#660">);</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#800">// initialization by =
the constructor.</span><span style=3D"color:#000"><br><br></span><span styl=
e=3D"color:#008">auto</span><span style=3D"color:#000"> p5 </span><span sty=
le=3D"color:#660">=3D</span><span style=3D"color:#000"> make_unqiue</span><=
span style=3D"color:#660"><</span><span style=3D"color:#606">Type</span>=
<span style=3D"color:#660">>(~{</span><span style=3D"color:#066">2</span=
><span style=3D"color:#660">,</span><span style=3D"color:#000"> </span><spa=
n style=3D"color:#066">1</span><span style=3D"color:#660">});</span><span s=
tyle=3D"color:#000"><br></span><span style=3D"color:#800">// Compiler error=
; cannot initialize from an initializer_list constructor.</span><span style=
=3D"color:#000"><br></span></div></code></div><div><br>Why should `Type` be=
initialized via direct constructor initialization, while `Aggregate` has t=
o use your `~{}` syntax?</div></blockquote><div><br>That's because an aggre=
gate (as well as a container like std::vector<int>) can always be con=
sidered as a sequence of items (which can be initialized by the respective =
items of an initializer-list),</div></blockquote><div><br>No, it can't. It =
can only be initialized by an initializer_list if the aggregate is a sequen=
ce of items of the <i>same</i> type. Remember: std::initializer_list can on=
ly contain items of the same type.<br><br></div><blockquote class=3D"gmail_=
quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pa=
dding-left: 1ex;"><div>while a constructor with two parameters doesn't nece=
ssarily perform an itemwise initialization of some sequence. If we want to =
support an itemwise initialization, we could express this intent explicitly=
by defining a special constructor:<br><br> struct Type<b=
r> {<br> int x,=
y;<br> Type(int _x, int _y) : //=
(1)<br> =
Type(~{_x, _y}) {}<br> Type(std::=
braced_init_list<int const &, int const &> &&li) : //=
(2)<br> =
_x(li.get<0>()), _y(li.get<1>()) {}<br> };<br=
><br> auto p =3D make_unqiue<Type>(~{2, 1}); // OK:=
calls (2)<br> </div><blockquote class=3D"gmail_quote" style=3D"margin=
:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div> Tha=
t's not uniform</div></blockquote><div><br>That's intentionally non-uniform=
..<br></div></blockquote><div><br>Please read the thread title. It's called,=
"RFC: Towards More Uniform Initialization Proposal". The thread is about a=
fix to uniform initialization syntax to make it more uniform and more unif=
ormly useable.<br><br>Your non-uniform commentary and suggestions are unhel=
pful. Please take your discussion of non-uniform initialization syntax else=
where. Your continued thread derailment is starting to border on trolling a=
t this point, since I have <i>repeatedly</i> ask you to stop bringing these=
things up.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin:=
0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><bloc=
kquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-lef=
t:1px #ccc solid;padding-left:1ex"><blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div> Are there any other tasks for which {lc: ...} would be useful?<=
/div></blockquote></blockquote><div><br>I was going to ask about {cl: ...}=
, but I made a typo :-)<br></div></blockquote><div><br>As I pointed out in =
the proposal, it's about orthogonality. You need {lc:} because that's the d=
efault behavior, which can't be changed. Adding {cl:} makes sense because i=
t's expected given that you have {lc:}. It would seem like a missing featur=
e otherwise.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin=
: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><blo=
ckquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-le=
ft:1px #ccc solid;padding-left:1ex"><div>I don't second-guess Bjarne Strous=
trup. {lc:} is the current behavior, and he clearly thought it was reasonab=
le for some reason.<br></div></blockquote><div><br>I have a simple explanat=
ion of that current behavior: the items of the paragraph 8.5.4/3 are ordere=
d in a way that for every particular case of application of list-initializa=
tion give us the behavior which would be the most likely expected (in opini=
on of the authors of the rules) among possible alternatives. In spite of th=
at, list-initialization (being used solely) does not give us an ability to =
express every desirable way of initialization and often we get an unexpecte=
d behavior.</div></blockquote><div><br>You're simply reiterating the purpos=
e of this proposal: to fix the small issues in what is otherwise a great in=
itialization syntax, thus allowing the user to express "every desirable way=
of initialization". </div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_582_17079790.1357559553242--
.
Author: Fernando Pelliccioni <fpelliccioni@gmail.com>
Date: Mon, 7 Jan 2013 10:15:29 -0300
Raw View
--14dae93410b9868f4b04d2b29f8b
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Sun, Dec 30, 2012 at 6:49 PM, Nicol Bolas <jmckesson@gmail.com> wrote:
> What follows is a draft of a proposal for adding new rules for uniform
> initialization syntax. It covers what it wants pretty well, so I'll let i=
t
> speak for itself.
>
> Introduction
>
> Braced-init-lists were originally used in object initialization with
> aggregate initialization. In the development of C++11, the idea was
> extended to include non-aggregate types through the use of a special
> initializer_list type.
>
> This idea was ultimately extended into what became known as uniform
> initialization: one could initially any type via the use of a
> braced-init-list. Doing so provides a number of advantages, among them is
> uniform initialization behavior and the elimination of the most vexing
> parse. In a perfect world, we would always use uniform initialization and
> never use direct constructor syntax.
>
> However, despite being called =93uniform initialization,=94 it cannot be
> uniformly used everywhere, due to a critical flaw that prevents its use
> towards these ends. This proposal intends to correct this flaw, thus
> allowing it to be used in all possible cases of object construction, whil=
e
> having well-defined results.
> Motivation and Scope
>
> The flaw in uniform initialization is quite simple to see in the standard
> library. The std::vector type has an explicit constructor which takes a
> single std::vector::size_type, which is an integral type. std::vectoralso=
has a constructor that takes an
> initializer_list<T>.
>
> For most types, these constructors can coexist with uniform initializatio=
n
> quite reasonably. For example:
>
> std::vector<A> v1{20};
> std::vector<A> v2{A{}};
> std::vector<A> v3{A{}, A{}, A{}};
>
> In this example, v1 is an array of 20 value-constructed values. v2 is an
> array of 1 value-constructed element. v3 is an array of 3
> value-constructed elements.
>
> This is all well and good, until we do this:
>
> std::vector<int> v1{20};
> std::vector<int> v2{int{}};
> std::vector<int> v3{int{}, int{}, int{}};
>
> v2 and v3 retain their old meaning. But v1 is now very different. It is
> an array containing a single element, the number 20. Why?
>
> Because uniform initialization syntax always prefers initializer list
> constructors if one is available that would fit the braced-init-list. Thi=
s
> is a consequence of uniform initialization syntax using the same syntax a=
s
> initializer lists: the braced-init-list. And since
> std::vector<int>::vector(std::initializer_list<int>) matches the
> braced-init-list ({20}), it will be preferred over
> std::vector<int>::vector(std::vector<int>::size_type)
>
> This is a problem because there is *no way* to get at the size_typeconstr=
uctor via uniform initialization. There is no syntax that we can
> employ which will cause the conflicting initializer_list constructor to
> be ignored or to do anything else that would allow us to get at a differe=
nt
> set of constructors.
>
> Now, this may seem like a rather unimportant issue. After all, if I know
> that I have to use constructor initialization with vector<int>, then I
> can simply do that. But consider code that is generic on the vector's
> type:
>
> template<typename T>
> std::vector<T> MakeVector()
> {
> return std::vector<T>{20};
> }
>
> By all rights, this code should always do the same thing: return a vector=
containing 20 value-initialized elements. But it does not.
> MakeVector<int>() will return a vector containing exactly one element.
>
> This is of much greater concern when dealing with more intricate
> templates. Consider the following trivial template function:
>
> template<typename T>
> T Process()
> {
> T t{};
> //do stuff with t;
> return T{t};
> }
>
> This function creates a temporary, does some processing, and returns a
> copy of it. This function requires that T be DefaultConstructible and
> CopyConstructible, in addition to whatever =93do stuff with t=94 requires=
..
>
> The problem is the last line. This line *may* violate the concept
> constraint. Why? Because there is no guarantee that T does *not* have an
> initializer_list constructor that can match with a T. For an example of
> such a class, consider std::vector<std::function<void()>> as our T.
>
> The problem is that std::function has a non-explicit constructor that can
> take *any* type that is CopyConstructible. And std::vector<std::function>=
is CopyConstructible. Therefore, this will call the initializer_list
> constructor. But the template function should not be calling the
> initializer list constructor; it's not part of the allowed interface to T=
..
> Therefore, Process violates the concept constraint, through no fault on
> the user's part.
>
> What this means is that you cannot use uniform initialization in generic
> code where the exact type of the object being constructed is derived from=
a
> template parameter. This is because there is no way for the user to
> explicitly choose which constructors to call.
> Design Overview
>
> The idea is quite simple. We will divide braced-init-list up into two
> variation: list-braced-init-list and constr-braced-init-list. Most of the
> text will remain the exact same, as they have almost identical behavior.
>
> The difference is that 13.3.1.7's list initialization overload resolution
> rules will behave differently. list-braced-init-list initialization will
> work exactly as it does. constr-braced-init-list will work opposite to th=
e
> current way. That is, it will check non-initializer_list constructors
> first, then go to the initializer_list ones if no matching constructors a=
re
> found. All other uses will work identically; you can use these for
> aggregate initialization and so forth just as before.
>
> The big issue is how constr-braced-init-lists are defined in the grammar.
> It should look like this:
>
> {^ ... }
>
> The =93{=94 token followed by the =93^=94 token is what distinguishes the
> constr-braced-init-list from a list-braced-init-list.
> Note
>
> I have no particular love for the use of =93^=94 here. My reasons for its
> selection are listed in the Grammar section of the Design Discussions
> segment of the document.
> Impact on the Standard
>
> Depending on how we want to handle the wording, we may need a new set of =
=93
> list-initialization=94 types. 13.3.1.7 never mentions braced-init-list; i=
t
> only operates in terms of list-initialization, which stems from a specifi=
c
> use of braced-init-list. We could have it say something like =93if the
> braced-init-list that issues this constructor is a list-braced-init-list,
> then ...=94 Or we could provide different forms of =93list-initialization=
..=94
>
> It should cause zero backwards compatibility problems.
> list-braced-init-lists should have the same behavior as before. Also, see
> the Design Decisions section, the Grammar part.
> Design Decisions
> Bikeshedding
>
> Finding the right grammar for this will likely be the biggest stumbling
> point. I would say that the most important metrics for a good piece of
> grammar are:
>
> -
>
> Backwards compatibility. Whatever grammar we use, it should be
> something that would have been illegal in C++11, no matter what litera=
ls,
> identifiers, and tokens come after it.
> -
>
> Brevity. It should be used a lot, so it shouldn't take up a lot of
> space.
>
> This leaves few candidates. Here are some potential alternatives:
>
> { explicit ... } //Keyword makes it clear what's going on.
> {, ...} //Comma at the start would normally be illegal.
> {| ...}
>
> We could in theory use any operator that only has a binary operation mode=
..
> The use of =93^=94 could interfere with C++/CX and other similar library
> extensions, so =93|=94 or some other operator would be acceptable.
>
> The operator should probably be within the braces, as this makes it more
> explicit which is being used.
> Library vs Language
>
> Originally, I considered a library-based solution to the issue. This woul=
d
> have required adding a special opaque type taken as a parameter to variou=
s
> calls. Since the opaque type is different from other types, it would
> prevent the braced-init-list from binding to an initializer_listconstruct=
or, thus disambiguating the call.
>
> This is problematic for two reasons. First, it adds some complexity to
> various container classes, as they have to prevent the user from using th=
e
> opaque type as the member or allocator types. But the primary reason that
> this is not a good solution is because it only solves the problem for the
> standard library.
>
> We should not ask every user who writes an initializer_list constructor
> to go though and add a suffix parameter to various functions. This is a
> problem introduced by the language, and it is best solved in the language=
..
> Alternate Designs
>
> constr-braced-init-list, in the current design, is intended to work
> exactly like braced-init-list except for which constructors hide which.
> That is, it could still access initializer_list constructors.
>
> We don't have to do that. There are two other alternatives. We could make
> constr-braced-init-list *never* use initializer list constructors. This
> would be more uniform in some respects:
>
> vector<int> v1{20}; //Creates an array of 1 item.
> vector<int> v2{^20}; //Creates an array of 20 items.
> vector<int> v3{20, 30, 40}; //Creates an array of 3 items.
> vector<int> v4{^20, 30, 40}; //Creates an array of 3 items.
>
> The oddball here is v2, which calls a constructor. It would be more
> uniform to require this:
>
> vector<int> v1{{^20}}; //Creates an array of 1 item.
> vector<int> v2{^20}; //Creates an array of 20 items.
> vector<int> v1{^{20, 30, 40}}; //Creates an array of 3 items.
> vector<int> v1{^20, 30, 40}; //Compiler error; no appropriate constructor=
to call.
>
> The question then becomes whether constr-braced-init-list should retain
> the *other* similarities to regular braced-init-lists. Should this be
> allowed:
>
> array<int, 3> a1{^10, 20, 30};
>
> That is, do we want to forbid constr-braced-init-lists from initializing
> with anything other than non-initializer_list constructors?
>
> I would say no, and here is why.
>
> Currently, std::allocator_traits::construct is defined in terms of
> calling new(/*stuff*/) T(std::forward<Args>(args)...). That will call
> constructors, but it will *only* call constructors. If we have a simple
> struct that could use aggregate initialization, we cannot use, for exampl=
e,
> emplace on it:
>
> struct Agg {int first, int second};
>
> std::vector<Agg> ag{{10, 20}, {20, 30}, {30, 40}}; //Aggregate initializa=
tion is OK here.
> ag.emplace_back(10, 20); //Error: no aggregate initialization is possible=
..
>
> There is no reason why we shouldn't be able to do this. To have this, we
> would need to be able to have std::allocator_traits::construct use unifor=
m
> initialization syntax: new(/*stuff*/) T{std::forward<Args>(args)...}.
> However, this can hide constructors; vector<vector<int>>::emplace_back(10=
)will add a vector containing one element. This will break existing
> applications, not to mention make it completely impossible to access the
> hidden constructors via emplace.
>
> By defining constr-braced-init-lists as being exactly equal to
> braced-init-list except for which constructors it prefers, it makes it
> possible to redefine std::allocator_traits::construct in terms of
> constr-braced-init-lists. This now means that the emplace calls can
> access aggregate initialization if the type supports it.
> Change the Definition
>
> There was an alternate design to resolve the issue. Simply declare that
> non-initializer_list constructors have priority, instead of the other way
> around. This would make these completely unambiguous:
>
> std::vector<int> v1{20};
> std::vector<int> v2{{20}};
>
> v1 is using the size_type constructor. v2 is clearly calling a
> single-argument constructor using a braced-init-list.
>
> The obvious problem with this is that it is a breaking change and a *
> silent* one at that.
>
> Even worse, it doesn't look uniform:
>
> std::array<int, 6> a1 =3D {1, 2, 3, 4, 5, 6}; //Brace elision removes the=
extra pair.
> std::vector<int> v1 =3D {1, 2, 3, 4, 5, 6}; //Brace "elision" possible.
> std::array<int, 1> a2 =3D {1}; //Brace elision still works.
> std::vector<int> v2 =3D {1}; //Brace "elision" no longer possible due t=
o conflict. Does the wrong thing.
>
> Honestly, this would be the preferable solution, if it were not a breakin=
g
> change. But it is, so we probably shouldn't do it.
>
> --
>
>
>
>
Hi Nicolas,
I think your proposal combined with "Named Arguments" (I can not find the
paper) could be useful.
I don't know the details of the "Named Arguments" proposal, but, from
Bjarne's "The Design and Evolution of C++" Section 6.5.1:
"Roland Hartinger's proposal for keyword arguments, that is, for a
mechanism for specifying arguments by name in a call, was close to
technically perfect. The reason the proposal was withdrawn rather than
accepted is therefore particularly interesting. ..."
Without having analyzed in depth, I imagine something like this:
vector<int> v1{20}; //Creates an array of 1 item.
vector<int> v2{ count :=3D 20 }; //Creates an array of 20 items.
vector<int> v3{20, 30, 40}; //Creates an array of 3 items.
I think this syntax is clearer, less ugly and also gives us an excuse to
incorporate "Named Arguments" into the language.
Regards,
Fernando Pelliccioni.
--=20
--14dae93410b9868f4b04d2b29f8b
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><div class=3D"gmail_extra"><br><br><div class=3D"gmail=
_quote">On Sun, Dec 30, 2012 at 6:49 PM, Nicol Bolas <span dir=3D"ltr"><=
<a href=3D"mailto:jmckesson@gmail.com" target=3D"_blank">jmckesson@gmail.co=
m</a>></span> wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-=
left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p=
adding-left:1ex">What follows is a draft of a proposal for adding new rules=
for uniform initialization syntax. It covers what it wants pretty well, so=
I'll let it speak for itself.<br>
<br><div title=3D"Introduction"><div><div><div><h2 style=3D"clear:both"><a =
name=3D"13bedca674f9352c_d0e6"></a>Introduction</h2></div></div></div><p>Br=
aced-init-lists were originally used in object initialization with aggregat=
e
initialization. In the development of C++11, the idea was exten=
ded to include
non-aggregate types through the use of a special <span>initiali=
zer_list</span>
type.</p><p>This idea was ultimately extended into what became =
known as uniform initialization:
one could initially any type via the use of a braced-init-list.=
Doing so provides a
number of advantages, among them is uniform initialization beha=
vior and the elimination
of the most vexing parse. In a perfect world, we would always u=
se uniform initialization
and never use direct constructor syntax.</p><p>However, despite=
being called <span>=93<span>uniform initialization,</span>=94</span> it ca=
nnot be
uniformly used everywhere, due to a critical flaw that prevents=
its use towards these
ends. This proposal intends to correct this flaw, thus allowing=
it to be used in all
possible cases of object construction, while having well-define=
d results.</p></div><div title=3D"Motivation and Scope"><div><div><div><h2 =
style=3D"clear:both"><a name=3D"13bedca674f9352c_d0e21"></a>Motivation and =
Scope</h2>
</div></div></div><p>The flaw in uniform initialization is quite simple to =
see in the standard library. The
<span>std::vector</span> type has an explicit constructor w=
hich takes a single
<span>std::vector::size_type</span>, which is an integral t=
ype.
<span>std::vector</span> also has a constructor that takes =
an
<span>initializer_list<T></span>.</p><p>For most type=
s, these constructors can coexist with uniform initialization quite
reasonably. For example:</p><pre>std::vector<A> v1{20};
std::vector<A> v2{A{}};
std::vector<A> v3{A{}, A{}, A{}};</pre><p>In this example, <code>v1</=
code> is an array of 20 value-constructed values.
<code>v2</code> is an array of 1 value-constructed element.
<code>v3</code> is an array of 3 value-constructed elements=
..</p><p>This is all well and good, until we do this:</p><pre>std::vector<=
;int> v1{20};
std::vector<int> v2{int{}};
std::vector<int> v3{int{}, int{}, int{}};</pre><p><code>v2</code> and=
<code>v3</code> retain their old meaning. But
<code>v1</code> is now very different. It is an array conta=
ining a single
element, the number 20. Why?</p><p>Because uniform initializati=
on syntax always prefers initializer list constructors if
one is available that would fit the braced-init-list. This is a=
consequence of uniform
initialization syntax using the same syntax as initializer list=
s: the braced-init-list.
And since
<code>std::vector<int>::vector(std::initializer_list&=
lt;int>)</code>
matches the braced-init-list (<code>{20}</code>), it will be pr=
eferred over
<code>std::vector<int>::vector(std::vector<int>=
::size_type)</code></p><p>This is a problem because there is <span><em>no w=
ay</em></span> to get at the
<span>size_type</span> constructor via uniform initializati=
on. There is no syntax
that we can employ which will cause the conflicting <span>initi=
alizer_list</span>
constructor to be ignored or to do anything else that would all=
ow us to get at a
different set of constructors.</p><p>Now, this may seem like a =
rather unimportant issue. After all, if I know that I have
to use constructor initialization with <span>vector<int><=
/span>, then I can simply do
that. But consider code that is generic on the <span>vector</sp=
an>'s type:</p><pre>template<typename T>
std::vector<T> MakeVector()
{
return std::vector<T>{20};
}</pre><p>By all rights, this code should always do the same thing: return =
a <span>vector</span>
containing 20 value-initialized elements. But it does not.
<code>MakeVector<int>()</code> will return a <span>ve=
ctor</span>
containing exactly one element.</p><p>This is of much greater c=
oncern when dealing with more intricate templates. Consider
the following trivial template function:</p><pre>template<ty=
pename T>
T Process()
{
T t{};
//do stuff with t;
return T{t};
}</pre><p>This function creates a temporary, does some processing, and retu=
rns a copy of it.
This function requires that <span>T</span> be DefaultConstructi=
ble and
CopyConstructible, in addition to whatever <span>=93<span>do st=
uff with t</span>=94</span>
requires.</p><p>The problem is the last line. This line <span><=
em>may</em></span> violate the concept
constraint. Why? Because there is no guarantee that <span>T</sp=
an> does
<span><em>not</em></span> have an <span>initializer_list</s=
pan> constructor that can
match with a <span>T</span>. For an example of such a class, co=
nsider
<span>std::vector<std::function<void()>></span>=
as our <span>T</span>.</p><p>The problem is that <span>std::function</span=
> has a non-explicit constructor that can
take <span><em>any</em></span> type that is CopyConstructible. =
And
<span>std::vector<std::function></span> is CopyConstr=
uctible. Therefore, this
will call the initializer_list constructor. But the template fu=
nction should not be
calling the initializer list constructor; it's not part of =
the allowed interface to T.
Therefore, <code>Process</code> violates the concept constraint=
, through no
fault on the user's part.</p><p>What this means is that you=
cannot use uniform initialization in generic code where
the exact type of the object being constructed is derived from =
a template parameter.
This is because there is no way for the user to explicitly choo=
se which constructors to
call.</p></div><div title=3D"Design Overview"><div><div><div><h=
2 style=3D"clear:both"><a name=3D"13bedca674f9352c_d0e160"></a>Design Overv=
iew</h2></div></div></div><p>The idea is quite simple. We will divide brace=
d-init-list up into two variation:
list-braced-init-list and constr-braced-init-list. Most of the =
text will remain the
exact same, as they have almost identical behavior.</p><p>The d=
ifference is that 13.3.1.7's list initialization overload resolution ru=
les will
behave differently. list-braced-init-list initialization will w=
ork exactly as it does.
constr-braced-init-list will work opposite to the current way. =
That is, it will check
non-initializer_list constructors first, then go to the initial=
izer_list ones if no
matching constructors are found. All other uses will work ident=
ically; you can use these
for aggregate initialization and so forth just as before.</p><p=
>The big issue is how constr-braced-init-lists are defined in the grammar. =
It should
look like this:</p><pre>{^ ... }</pre><p>The <span>=93<span>{</=
span>=94</span> token followed by the <span>=93<span>^</span>=94</span> tok=
en is what
distinguishes the constr-braced-init-list from a list-braced-in=
it-list.</p><div title=3D"Note" style=3D"margin-left:0.5in;margin-right:0.5=
in"><h3>Note</h3><p>I have no particular love for the use of <span>=93<span=
>^</span>=94</span> here. My reasons for its
selection are listed in the Grammar section of the Design D=
iscussions segment of the
document.</p></div></div><div title=3D"Impact on the Standa=
rd"><div><div><div><h2 style=3D"clear:both"><a name=3D"13bedca674f9352c_d0e=
185"></a>Impact on the Standard</h2></div></div></div><p>Depending on how w=
e want to handle the wording, we may need a new set of
<span>=93<span>list-initialization</span>=94</span> types. =
13.3.1.7 never mentions braced-init-list;
it only operates in terms of list-initialization, which stems f=
rom a specific use of
braced-init-list. We could have it say something like <span>=93=
<span>if the braced-init-list
that issues this constructor is a list-braced-init-list, th=
en ...</span>=94</span> Or we
could provide different forms of <span>=93<span>list-initializa=
tion.</span>=94</span></p><p>It should cause zero backwards compatibility p=
roblems. list-braced-init-lists should
have the same behavior as before. Also, see the Design Decision=
s section, the Grammar
part.</p></div><div title=3D"Design Decisions"><div><div><div><=
h2 style=3D"clear:both"><a name=3D"13bedca674f9352c_d0e200"></a>Design Deci=
sions</h2></div></div></div><div title=3D"Bikeshedding"><div><div><div><h3>=
<a name=3D"13bedca674f9352c_d0e203"></a>Bikeshedding</h3>
</div></div></div><p>Finding the right grammar for this will likely be the =
biggest stumbling point. I
would say that the most important metrics for a good piece =
of grammar are:</p><div><ul type=3D"disc"><li><p>Backwards compatibility. W=
hatever grammar we use, it should be something
that would have been illegal in C++11, no matter wh=
at literals, identifiers,
and tokens come after it.</p></li><li><p>Brevity. I=
t should be used a lot, so it shouldn't take up a lot of
space.</p></li></ul></div><p>This leaves few candid=
ates. Here are some potential alternatives:</p><pre>{ explicit ... } //Keyw=
ord makes it clear what's going on.
{, ...} //Comma at the start would normally be illegal.
{| ...}
</pre><p>We could in theory use any operator that only has a binary operati=
on mode. The use
of <span>=93<span>^</span>=94</span> could interfere with C=
++/CX and other similar library
extensions, so <span>=93<span>|</span>=94</span> or some ot=
her operator would be acceptable.</p><p>The operator should probably be wit=
hin the braces, as this makes it more explicit
which is being used.</p></div><div title=3D"Library vs Lang=
uage"><div><div><div><h3><a name=3D"13bedca674f9352c_d0e229"></a>Library vs=
Language</h3></div></div></div><p>Originally, I considered a library-based=
solution to the issue. This would have
required adding a special opaque type taken as a parameter =
to various calls. Since
the opaque type is different from other types, it would pre=
vent the braced-init-list
from binding to an <span>initializer_list</span> constructo=
r, thus disambiguating
the call.</p><p>This is problematic for two reasons. First,=
it adds some complexity to various
container classes, as they have to prevent the user from us=
ing the opaque type as
the member or allocator types. But the primary reason that =
this is not a good
solution is because it only solves the problem for the stan=
dard library.</p><p>We should not ask every user who writes an <span>initia=
lizer_list</span>
constructor to go though and add a suffix parameter to vari=
ous functions. This is a
problem introduced by the language, and it is best solved i=
n the language.</p></div><div title=3D"Alternate Designs"><div><div><div><h=
3><a name=3D"13bedca674f9352c_d0e244"></a>Alternate Designs</h3></div></div=
>
</div><p>constr-braced-init-list, in the current design, is intended to wor=
k exactly like
braced-init-list except for which constructors hide which. =
That is, it could still
access <span>initializer_list</span> constructors.</p><p>We=
don't have to do that. There are two other alternatives. We could make
constr-braced-init-list <span><em>never</em></span> use ini=
tializer list
constructors. This would be more uniform in some respects:<=
/p><pre>vector<int> v1{20}; //Creates an array of 1 item.
vector<int> v2{^20}; //Creates an array of 20 items.
vector<int> v3{20, 30, 40}; //Creates an array of 3 items.
vector<int> v4{^20, 30, 40}; //Creates an array of 3 items.</pre><p>T=
he oddball here is <code>v2</code>, which calls a constructor. It would be
more uniform to require this:</p><pre>vector<int> v1{=
{^20}}; //Creates an array of 1 item.
vector<int> v2{^20}; //Creates an array of 20 items.
vector<int> v1{^{20, 30, 40}}; //Creates an array of 3 items.
vector<int> v1{^20, 30, 40}; //Compiler error; no appropriate constru=
ctor to call.</pre><p>The question then becomes whether constr-braced-init-=
list should retain the
<span><em>other</em></span> similarities to regular bra=
ced-init-lists. Should
this be allowed:</p><pre>array<int, 3> a1{^10, 20, 30=
};</pre><p>That is, do we want to forbid constr-braced-init-lists from init=
ializing with
anything other than non-initializer_list constructors?</p><=
p>I would say no, and here is why.</p><p>Currently, <code>std::allocator_tr=
aits::construct</code> is defined in
terms of calling <code>new(/*stuff*/)
T(std::forward<Args>(args)...)</code>. That will call=
constructors, but it
will <span><em>only</em></span> call constructors. If we ha=
ve a simple struct that
could use aggregate initialization, we cannot use, for exam=
ple,
<code>emplace</code> on it:</p><pre>struct Agg {int fir=
st, int second};
std::vector<Agg> ag{{10, 20}, {20, 30}, {30, 40}}; //Aggregate initia=
lization is OK here.
ag.emplace_back(10, 20); //Error: no aggregate initialization is possible.<=
/pre><p>There is no reason why we shouldn't be able to do this. To have=
this, we would
need to be able to have std::allocator_traits::construct us=
e uniform initialization
syntax: <code>new(/*stuff*/) T{std::forward<Args>(arg=
s)...}</code>.
However, this can hide constructors;
<code>vector<vector<int>>::emplace_back(10)=
</code> will add a vector
containing one element. This will break existing applicatio=
ns, not to mention make
it completely impossible to access the hidden constructors =
via
<code>emplace</code>.</p><p>By defining constr-braced-i=
nit-lists as being exactly equal to braced-init-list
except for which constructors it prefers, it makes it possi=
ble to redefine
<code>std::allocator_traits::construct</code> in terms =
of
<code>constr-braced-init-lists</code>. This now means t=
hat the
<code>emplace</code> calls can access aggregate initial=
ization if the
type supports it.</p></div><div title=3D"Change the Definit=
ion"><div><div><div><h3><a name=3D"13bedca674f9352c_d0e315"></a>Change the =
Definition</h3></div></div></div><p>There was an alternate design to resolv=
e the issue. Simply declare that
non-<span>initializer_list</span> constructors have pri=
ority, instead of the
other way around. This would make these completely unambigu=
ous:</p><pre>std::vector<int> v1{20};
std::vector<int> v2{{20}};</pre><p><span>v1</span> is using the <span=
>size_type</span> constructor. <span>v2</span>
is clearly calling a single-argument constructor using a br=
aced-init-list.</p><p>The obvious problem with this is that it is a breakin=
g change and a
<span><em>silent</em></span> one at that.</p><p>Even wo=
rse, it doesn't look uniform:</p><pre>std::array<int, 6> a1 =3D {=
1, 2, 3, 4, 5, 6}; //Brace elision removes the extra pair.
std::vector<int> v1 =3D {1, 2, 3, 4, 5, 6}; //Brace "elision&quo=
t; possible.
std::array<int, 1> a2 =3D {1}; //Brace elision still works.
std::vector<int> v2 =3D {1}; //Brace "elision" no longer =
possible due to conflict. Does the wrong thing.</pre><p>Honestly, this woul=
d be the preferable solution, if it were not a breaking change.
But it is, so we probably shouldn't do it.</p></div></d=
iv><span class=3D""><font color=3D"#888888">
<p></p>
-- <br>
=A0<br>
=A0<br>
=A0<br></font></span></blockquote><div><br></div><div><div>Hi Nicolas,</div=
><div><br></div><div>I think your proposal combined with "Named Argume=
nts" (I can not find the paper) could be useful.</div><div><br></div>
<div>I don't know the details of the "Named Arguments" propos=
al, but, from Bjarne's "The Design and Evolution of C++" Sect=
ion 6.5.1:</div><div>"Roland Hartinger's proposal for keyword argu=
ments, that is, for a</div>
<div>mechanism for specifying arguments by name in a call, was close to</di=
v><div>technically perfect. The reason the proposal was withdrawn rather th=
an</div><div>accepted is therefore particularly interesting. ..."</div=
>
<div><br></div><div><br></div><div>Without having analyzed in depth, I imag=
ine something like this:</div><div><br></div><div>vector<int> v1{20};=
=A0 =A0 =A0 =A0 =A0 =A0 //Creates an array of 1 item.</div><div>vector<=
int> v2{ count :=3D 20 }; =A0//Creates an array of 20 items.</div>
<div>vector<int> v3{20, 30, 40}; =A0 =A0 //Creates an array of 3 item=
s.</div><div><br></div><div><br></div><div>I think this syntax is clearer, =
less ugly and also gives us an excuse to incorporate "Named Arguments&=
quot; into the language.</div>
<div><br></div><div>Regards,</div><div>Fernando Pelliccioni.</div></div><di=
v>=A0</div></div><br></div></div>
<p></p>
-- <br />
<br />
<br />
<br />
--14dae93410b9868f4b04d2b29f8b--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Mon, 7 Jan 2013 13:35:00 -0800 (PST)
Raw View
------=_Part_390_26361578.1357594500476
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Monday, January 7, 2013 5:15:29 AM UTC-8, Fernando Pelliccioni wrote:
>
> On Sun, Dec 30, 2012 at 6:49 PM, Nicol Bolas <jmck...@gmail.com<javascrip=
t:>
> > wrote:
>
>> What follows is a draft of a proposal for adding new rules for uniform=
=20
>> initialization syntax. It covers what it wants pretty well, so I'll let =
it=20
>> speak for itself.
>>
>> Introduction
>>
>> Braced-init-lists were originally used in object initialization with=20
>> aggregate initialization. In the development of C++11, the idea was=20
>> extended to include non-aggregate types through the use of a special=20
>> initializer_list type.
>>
>> This idea was ultimately extended into what became known as uniform=20
>> initialization: one could initially any type via the use of a=20
>> braced-init-list. Doing so provides a number of advantages, among them i=
s=20
>> uniform initialization behavior and the elimination of the most vexing=
=20
>> parse. In a perfect world, we would always use uniform initialization an=
d=20
>> never use direct constructor syntax.
>>
>> However, despite being called =93uniform initialization,=94 it cannot be=
=20
>> uniformly used everywhere, due to a critical flaw that prevents its use=
=20
>> towards these ends. This proposal intends to correct this flaw, thus=20
>> allowing it to be used in all possible cases of object construction, whi=
le=20
>> having well-defined results.
>> Motivation and Scope=20
>>
>> The flaw in uniform initialization is quite simple to see in the standar=
d=20
>> library. The std::vector type has an explicit constructor which takes a=
=20
>> single std::vector::size_type, which is an integral type. std::vectorals=
o has a constructor that takes an=20
>> initializer_list<T>.
>>
>> For most types, these constructors can coexist with uniform=20
>> initialization quite reasonably. For example:
>>
>> std::vector<A> v1{20};
>> std::vector<A> v2{A{}};
>> std::vector<A> v3{A{}, A{}, A{}};
>>
>> In this example, v1 is an array of 20 value-constructed values. v2 is an=
=20
>> array of 1 value-constructed element. v3 is an array of 3=20
>> value-constructed elements.
>>
>> This is all well and good, until we do this:
>>
>> std::vector<int> v1{20};
>> std::vector<int> v2{int{}};
>> std::vector<int> v3{int{}, int{}, int{}};
>>
>> v2 and v3 retain their old meaning. But v1 is now very different. It is=
=20
>> an array containing a single element, the number 20. Why?
>>
>> Because uniform initialization syntax always prefers initializer list=20
>> constructors if one is available that would fit the braced-init-list. Th=
is=20
>> is a consequence of uniform initialization syntax using the same syntax =
as=20
>> initializer lists: the braced-init-list. And since=20
>> std::vector<int>::vector(std::initializer_list<int>) matches the=20
>> braced-init-list ({20}), it will be preferred over=20
>> std::vector<int>::vector(std::vector<int>::size_type)
>>
>> This is a problem because there is *no way* to get at the size_typeconst=
ructor via uniform initialization. There is no syntax that we can=20
>> employ which will cause the conflicting initializer_list constructor to=
=20
>> be ignored or to do anything else that would allow us to get at a differ=
ent=20
>> set of constructors.
>>
>> Now, this may seem like a rather unimportant issue. After all, if I know=
=20
>> that I have to use constructor initialization with vector<int>, then I=
=20
>> can simply do that. But consider code that is generic on the vector's=20
>> type:
>>
>> template<typename T>
>> std::vector<T> MakeVector()
>> {
>> return std::vector<T>{20};
>> }
>>
>> By all rights, this code should always do the same thing: return a vecto=
rcontaining 20 value-initialized elements. But it does not.=20
>> MakeVector<int>() will return a vector containing exactly one element.
>>
>> This is of much greater concern when dealing with more intricate=20
>> templates. Consider the following trivial template function:
>>
>> template<typename T>
>> T Process()
>> {
>> T t{};
>> //do stuff with t;
>> return T{t};
>> }
>>
>> This function creates a temporary, does some processing, and returns a=
=20
>> copy of it. This function requires that T be DefaultConstructible and=20
>> CopyConstructible, in addition to whatever =93do stuff with t=94 require=
s.
>>
>> The problem is the last line. This line *may* violate the concept=20
>> constraint. Why? Because there is no guarantee that T does *not* have an=
=20
>> initializer_list constructor that can match with a T. For an example of=
=20
>> such a class, consider std::vector<std::function<void()>> as our T.
>>
>> The problem is that std::function has a non-explicit constructor that=20
>> can take *any* type that is CopyConstructible. And=20
>> std::vector<std::function> is CopyConstructible. Therefore, this will=20
>> call the initializer_list constructor. But the template function should =
not=20
>> be calling the initializer list constructor; it's not part of the allowe=
d=20
>> interface to T. Therefore, Process violates the concept constraint,=20
>> through no fault on the user's part.
>>
>> What this means is that you cannot use uniform initialization in generic=
=20
>> code where the exact type of the object being constructed is derived fro=
m a=20
>> template parameter. This is because there is no way for the user to=20
>> explicitly choose which constructors to call.
>> Design Overview
>>
>> The idea is quite simple. We will divide braced-init-list up into two=20
>> variation: list-braced-init-list and constr-braced-init-list. Most of th=
e=20
>> text will remain the exact same, as they have almost identical behavior.
>>
>> The difference is that 13.3.1.7's list initialization overload resolutio=
n=20
>> rules will behave differently. list-braced-init-list initialization will=
=20
>> work exactly as it does. constr-braced-init-list will work opposite to t=
he=20
>> current way. That is, it will check non-initializer_list constructors=20
>> first, then go to the initializer_list ones if no matching constructors =
are=20
>> found. All other uses will work identically; you can use these for=20
>> aggregate initialization and so forth just as before.
>>
>> The big issue is how constr-braced-init-lists are defined in the grammar=
..=20
>> It should look like this:
>>
>> {^ ... }
>>
>> The =93{=94 token followed by the =93^=94 token is what distinguishes th=
e=20
>> constr-braced-init-list from a list-braced-init-list.
>> Note
>>
>> I have no particular love for the use of =93^=94 here. My reasons for it=
s=20
>> selection are listed in the Grammar section of the Design Discussions=20
>> segment of the document.
>> Impact on the Standard
>>
>> Depending on how we want to handle the wording, we may need a new set of=
=20
>> =93list-initialization=94 types. 13.3.1.7 never mentions braced-init-lis=
t;=20
>> it only operates in terms of list-initialization, which stems from a=20
>> specific use of braced-init-list. We could have it say something like =
=93if=20
>> the braced-init-list that issues this constructor is a=20
>> list-braced-init-list, then ...=94 Or we could provide different forms o=
f =93
>> list-initialization.=94
>>
>> It should cause zero backwards compatibility problems.=20
>> list-braced-init-lists should have the same behavior as before. Also, se=
e=20
>> the Design Decisions section, the Grammar part.
>> Design Decisions
>> Bikeshedding=20
>>
>> Finding the right grammar for this will likely be the biggest stumbling=
=20
>> point. I would say that the most important metrics for a good piece of=
=20
>> grammar are:
>>
>> -=20
>> =20
>> Backwards compatibility. Whatever grammar we use, it should be=20
>> something that would have been illegal in C++11, no matter what liter=
als,=20
>> identifiers, and tokens come after it.
>> -=20
>> =20
>> Brevity. It should be used a lot, so it shouldn't take up a lot of=20
>> space.
>> =20
>> This leaves few candidates. Here are some potential alternatives:
>>
>> { explicit ... } //Keyword makes it clear what's going on.
>> {, ...} //Comma at the start would normally be illegal.
>> {| ...}
>>
>> We could in theory use any operator that only has a binary operation=20
>> mode. The use of =93^=94 could interfere with C++/CX and other similar=
=20
>> library extensions, so =93|=94 or some other operator would be acceptabl=
e.
>>
>> The operator should probably be within the braces, as this makes it more=
=20
>> explicit which is being used.
>> Library vs Language
>>
>> Originally, I considered a library-based solution to the issue. This=20
>> would have required adding a special opaque type taken as a parameter to=
=20
>> various calls. Since the opaque type is different from other types, it=
=20
>> would prevent the braced-init-list from binding to an initializer_listco=
nstructor, thus disambiguating the call.
>>
>> This is problematic for two reasons. First, it adds some complexity to=
=20
>> various container classes, as they have to prevent the user from using t=
he=20
>> opaque type as the member or allocator types. But the primary reason tha=
t=20
>> this is not a good solution is because it only solves the problem for th=
e=20
>> standard library.
>>
>> We should not ask every user who writes an initializer_list constructor=
=20
>> to go though and add a suffix parameter to various functions. This is a=
=20
>> problem introduced by the language, and it is best solved in the languag=
e.
>> Alternate Designs
>>
>> constr-braced-init-list, in the current design, is intended to work=20
>> exactly like braced-init-list except for which constructors hide which.=
=20
>> That is, it could still access initializer_list constructors.
>>
>> We don't have to do that. There are two other alternatives. We could mak=
e=20
>> constr-braced-init-list *never* use initializer list constructors. This=
=20
>> would be more uniform in some respects:
>>
>> vector<int> v1{20}; //Creates an array of 1 item.
>> vector<int> v2{^20}; //Creates an array of 20 items.
>> vector<int> v3{20, 30, 40}; //Creates an array of 3 items.
>> vector<int> v4{^20, 30, 40}; //Creates an array of 3 items.
>>
>> The oddball here is v2, which calls a constructor. It would be more=20
>> uniform to require this:
>>
>> vector<int> v1{{^20}}; //Creates an array of 1 item.
>> vector<int> v2{^20}; //Creates an array of 20 items.
>> vector<int> v1{^{20, 30, 40}}; //Creates an array of 3 items.
>> vector<int> v1{^20, 30, 40}; //Compiler error; no appropriate constructo=
r to call.
>>
>> The question then becomes whether constr-braced-init-list should retain=
=20
>> the *other* similarities to regular braced-init-lists. Should this be=20
>> allowed:
>>
>> array<int, 3> a1{^10, 20, 30};
>>
>> That is, do we want to forbid constr-braced-init-lists from initializing=
=20
>> with anything other than non-initializer_list constructors?
>>
>> I would say no, and here is why.
>>
>> Currently, std::allocator_traits::construct is defined in terms of=20
>> calling new(/*stuff*/) T(std::forward<Args>(args)...). That will call=20
>> constructors, but it will *only* call constructors. If we have a simple=
=20
>> struct that could use aggregate initialization, we cannot use, for examp=
le,=20
>> emplace on it:
>>
>> struct Agg {int first, int second};
>>
>> std::vector<Agg> ag{{10, 20}, {20, 30}, {30, 40}}; //Aggregate initializ=
ation is OK here.
>> ag.emplace_back(10, 20); //Error: no aggregate initialization is possibl=
e.
>>
>> There is no reason why we shouldn't be able to do this. To have this, we=
=20
>> would need to be able to have std::allocator_traits::construct use unifo=
rm=20
>> initialization syntax: new(/*stuff*/) T{std::forward<Args>(args)...}.=20
>> However, this can hide constructors;=20
>> vector<vector<int>>::emplace_back(10) will add a vector containing one=
=20
>> element. This will break existing applications, not to mention make it=
=20
>> completely impossible to access the hidden constructors via emplace.
>>
>> By defining constr-braced-init-lists as being exactly equal to=20
>> braced-init-list except for which constructors it prefers, it makes it=
=20
>> possible to redefine std::allocator_traits::construct in terms of=20
>> constr-braced-init-lists. This now means that the emplace calls can=20
>> access aggregate initialization if the type supports it.
>> Change the Definition
>>
>> There was an alternate design to resolve the issue. Simply declare that=
=20
>> non-initializer_list constructors have priority, instead of the other=20
>> way around. This would make these completely unambiguous:
>>
>> std::vector<int> v1{20};
>> std::vector<int> v2{{20}};
>>
>> v1 is using the size_type constructor. v2 is clearly calling a=20
>> single-argument constructor using a braced-init-list.
>>
>> The obvious problem with this is that it is a breaking change and a *
>> silent* one at that.
>>
>> Even worse, it doesn't look uniform:
>>
>> std::array<int, 6> a1 =3D {1, 2, 3, 4, 5, 6}; //Brace elision removes th=
e extra pair.
>> std::vector<int> v1 =3D {1, 2, 3, 4, 5, 6}; //Brace "elision" possible.
>> std::array<int, 1> a2 =3D {1}; //Brace elision still works.
>> std::vector<int> v2 =3D {1}; //Brace "elision" no longer possible due =
to conflict. Does the wrong thing.
>>
>> Honestly, this would be the preferable solution, if it were not a=20
>> breaking change. But it is, so we probably shouldn't do it.
>>
>> --=20
>> =20
>> =20
>> =20
>>
>
> Hi Nicolas,
>
> I think your proposal combined with "Named Arguments" (I can not find the=
=20
> paper) could be useful.
>
> I don't know the details of the "Named Arguments" proposal, but, from=20
> Bjarne's "The Design and Evolution of C++" Section 6.5.1:
> "Roland Hartinger's proposal for keyword arguments, that is, for a
> mechanism for specifying arguments by name in a call, was close to
> technically perfect. The reason the proposal was withdrawn rather than
> accepted is therefore particularly interesting. ..."
>
>
> Without having analyzed in depth, I imagine something like this:
>
> vector<int> v1{20}; //Creates an array of 1 item.
> vector<int> v2{ count :=3D 20 }; //Creates an array of 20 items.
> vector<int> v3{20, 30, 40}; //Creates an array of 3 items.
>
>
> I think this syntax is clearer, less ugly and also gives us an excuse to=
=20
> incorporate "Named Arguments" into the language.
>
Except that it doesn't really solve the actual problem in question. Observe=
:
vector<int> v1{20}; //Creates an array of 1 item.
vector<Type> v1{20}; //Creates an array 20 Types.
If you used {l:} instead:
vector<int> v1{l: 20}; //Creates an array of 1 item.
vector<Type> v1{l: 20}; //Compiler error; no matching=20
initializer_list constructor
Then you get a proper compiler error. The person doing the initialization=
=20
has the ability to explicitly state what they want to call and what they=20
don't.
Also, how does that work with aggregate initialization? Does it cause the=
=20
initialization of a particular named field of the aggregate?
Plus, there's the general issue with named parameters at all, which is a=20
very foreign concept to C++ in general. The idea of a template's concept=20
requiring a parameter name is very... disconcerting.
--=20
------=_Part_390_26361578.1357594500476
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
<br><br>On Monday, January 7, 2013 5:15:29 AM UTC-8, Fernando Pelliccioni w=
rote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><di=
v class=3D"gmail_quote">On Sun, Dec 30, 2012 at 6:49 PM, Nicol Bolas <span =
dir=3D"ltr"><<a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-ma=
ilto=3D"gbA2CvThCu8J">jmck...@gmail.com</a>></span> wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-=
left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p=
adding-left:1ex">What follows is a draft of a proposal for adding new rules=
for uniform initialization syntax. It covers what it wants pretty well, so=
I'll let it speak for itself.<br>
<br><div title=3D"Introduction"><div><div><div><h2 style=3D"clear:both"><a =
name=3D"CAKXPfp2GC-JZpVr_77Dc32EcFXwy5hjMHB5CNr-7g2n4dyf_mQ@mail.gmail.com_=
13bedca674f9352c_d0e6"></a>Introduction</h2></div></div></div><p>Braced-ini=
t-lists were originally used in object initialization with aggregate
initialization. In the development of C++11, the idea was exten=
ded to include
non-aggregate types through the use of a special <span>initiali=
zer_list</span>
type.</p><p>This idea was ultimately extended into what became =
known as uniform initialization:
one could initially any type via the use of a braced-init-list.=
Doing so provides a
number of advantages, among them is uniform initialization beha=
vior and the elimination
of the most vexing parse. In a perfect world, we would always u=
se uniform initialization
and never use direct constructor syntax.</p><p>However, despite=
being called <span>=93<span>uniform initialization,</span>=94</span> it ca=
nnot be
uniformly used everywhere, due to a critical flaw that prevents=
its use towards these
ends. This proposal intends to correct this flaw, thus allowing=
it to be used in all
possible cases of object construction, while having well-define=
d results.</p></div><div title=3D"Motivation and Scope"><div><div><div><h2 =
style=3D"clear:both"><a name=3D"CAKXPfp2GC-JZpVr_77Dc32EcFXwy5hjMHB5CNr-7g2=
n4dyf_mQ@mail.gmail.com_13bedca674f9352c_d0e21"></a>Motivation and Scope</h=
2>
</div></div></div><p>The flaw in uniform initialization is quite simple to =
see in the standard library. The
<span>std::vector</span> type has an explicit constructor w=
hich takes a single
<span>std::vector::size_type</span>, which is an integral t=
ype.
<span>std::vector</span> also has a constructor that takes =
an
<span>initializer_list<T></span>.</p><p>For most type=
s, these constructors can coexist with uniform initialization quite
reasonably. For example:</p><pre>std::vector<A> v1{20};
std::vector<A> v2{A{}};
std::vector<A> v3{A{}, A{}, A{}};</pre><p>In this example, <code>v1</=
code> is an array of 20 value-constructed values.
<code>v2</code> is an array of 1 value-constructed element.
<code>v3</code> is an array of 3 value-constructed elements=
..</p><p>This is all well and good, until we do this:</p><pre>std::vector<=
;int> v1{20};
std::vector<int> v2{int{}};
std::vector<int> v3{int{}, int{}, int{}};</pre><p><code>v2</code> and=
<code>v3</code> retain their old meaning. But
<code>v1</code> is now very different. It is an array conta=
ining a single
element, the number 20. Why?</p><p>Because uniform initializati=
on syntax always prefers initializer list constructors if
one is available that would fit the braced-init-list. This is a=
consequence of uniform
initialization syntax using the same syntax as initializer list=
s: the braced-init-list.
And since
<code>std::vector<int>::vector(std::<wbr>initializer_=
list<int>)</code>
matches the braced-init-list (<code>{20}</code>), it will be pr=
eferred over
<code>std::vector<int>::vector(std::<wbr>vector<in=
t>::size_type)</code></p><p>This is a problem because there is <span><i>=
no way</i></span> to get at the
<span>size_type</span> constructor via uniform initializati=
on. There is no syntax
that we can employ which will cause the conflicting <span>initi=
alizer_list</span>
constructor to be ignored or to do anything else that would all=
ow us to get at a
different set of constructors.</p><p>Now, this may seem like a =
rather unimportant issue. After all, if I know that I have
to use constructor initialization with <span>vector<int><=
/span>, then I can simply do
that. But consider code that is generic on the <span>vector</sp=
an>'s type:</p><pre>template<typename T>
std::vector<T> MakeVector()
{
return std::vector<T>{20};
}</pre><p>By all rights, this code should always do the same thing: return =
a <span>vector</span>
containing 20 value-initialized elements. But it does not.
<code>MakeVector<int>()</code> will return a <span>ve=
ctor</span>
containing exactly one element.</p><p>This is of much greater c=
oncern when dealing with more intricate templates. Consider
the following trivial template function:</p><pre>template<ty=
pename T>
T Process()
{
T t{};
//do stuff with t;
return T{t};
}</pre><p>This function creates a temporary, does some processing, and retu=
rns a copy of it.
This function requires that <span>T</span> be DefaultConstructi=
ble and
CopyConstructible, in addition to whatever <span>=93<span>do st=
uff with t</span>=94</span>
requires.</p><p>The problem is the last line. This line <span><=
i>may</i></span> violate the concept
constraint. Why? Because there is no guarantee that <span>T</sp=
an> does
<span><i>not</i></span> have an <span>initializer_list</spa=
n> constructor that can
match with a <span>T</span>. For an example of such a class, co=
nsider
<span>std::vector<std::function<<wbr>void()>></=
span> as our <span>T</span>.</p><p>The problem is that <span>std::function<=
/span> has a non-explicit constructor that can
take <span><i>any</i></span> type that is CopyConstructible. An=
d
<span>std::vector<std::function></span> is CopyConstr=
uctible. Therefore, this
will call the initializer_list constructor. But the template fu=
nction should not be
calling the initializer list constructor; it's not part of the =
allowed interface to T.
Therefore, <code>Process</code> violates the concept constraint=
, through no
fault on the user's part.</p><p>What this means is that you can=
not use uniform initialization in generic code where
the exact type of the object being constructed is derived from =
a template parameter.
This is because there is no way for the user to explicitly choo=
se which constructors to
call.</p></div><div title=3D"Design Overview"><div><div><div><h=
2 style=3D"clear:both"><a name=3D"CAKXPfp2GC-JZpVr_77Dc32EcFXwy5hjMHB5CNr-7=
g2n4dyf_mQ@mail.gmail.com_13bedca674f9352c_d0e160"></a>Design Overview</h2>=
</div></div></div><p>The idea is quite simple. We will divide braced-init-l=
ist up into two variation:
list-braced-init-list and constr-braced-init-list. Most of the =
text will remain the
exact same, as they have almost identical behavior.</p><p>The d=
ifference is that 13.3.1.7's list initialization overload resolution rules =
will
behave differently. list-braced-init-list initialization will w=
ork exactly as it does.
constr-braced-init-list will work opposite to the current way. =
That is, it will check
non-initializer_list constructors first, then go to the initial=
izer_list ones if no
matching constructors are found. All other uses will work ident=
ically; you can use these
for aggregate initialization and so forth just as before.</p><p=
>The big issue is how constr-braced-init-lists are defined in the grammar. =
It should
look like this:</p><pre>{^ ... }</pre><p>The <span>=93<span>{</=
span>=94</span> token followed by the <span>=93<span>^</span>=94</span> tok=
en is what
distinguishes the constr-braced-init-list from a list-braced-in=
it-list.</p><div title=3D"Note" style=3D"margin-left:0.5in;margin-right:0.5=
in"><h3>Note</h3><p>I have no particular love for the use of <span>=93<span=
>^</span>=94</span> here. My reasons for its
selection are listed in the Grammar section of the Design D=
iscussions segment of the
document.</p></div></div><div title=3D"Impact on the Standa=
rd"><div><div><div><h2 style=3D"clear:both"><a name=3D"CAKXPfp2GC-JZpVr_77D=
c32EcFXwy5hjMHB5CNr-7g2n4dyf_mQ@mail.gmail.com_13bedca674f9352c_d0e185"></a=
>Impact on the Standard</h2></div></div></div><p>Depending on how we want t=
o handle the wording, we may need a new set of
<span>=93<span>list-initialization</span>=94</span> types. =
13.3.1.7 never mentions braced-init-list;
it only operates in terms of list-initialization, which stems f=
rom a specific use of
braced-init-list. We could have it say something like <span>=93=
<span>if the braced-init-list
that issues this constructor is a list-braced-init-list, th=
en ...</span>=94</span> Or we
could provide different forms of <span>=93<span>list-initializa=
tion.</span>=94</span></p><p>It should cause zero backwards compatibility p=
roblems. list-braced-init-lists should
have the same behavior as before. Also, see the Design Decision=
s section, the Grammar
part.</p></div><div title=3D"Design Decisions"><div><div><div><=
h2 style=3D"clear:both"><a name=3D"CAKXPfp2GC-JZpVr_77Dc32EcFXwy5hjMHB5CNr-=
7g2n4dyf_mQ@mail.gmail.com_13bedca674f9352c_d0e200"></a>Design Decisions</h=
2></div></div></div><div title=3D"Bikeshedding"><div><div><div><h3><a name=
=3D"CAKXPfp2GC-JZpVr_77Dc32EcFXwy5hjMHB5CNr-7g2n4dyf_mQ@mail.gmail.com_13be=
dca674f9352c_d0e203"></a>Bikeshedding</h3>
</div></div></div><p>Finding the right grammar for this will likely be the =
biggest stumbling point. I
would say that the most important metrics for a good piece =
of grammar are:</p><div><ul type=3D"disc"><li><p>Backwards compatibility. W=
hatever grammar we use, it should be something
that would have been illegal in C++11, no matter wh=
at literals, identifiers,
and tokens come after it.</p></li><li><p>Brevity. I=
t should be used a lot, so it shouldn't take up a lot of
space.</p></li></ul></div><p>This leaves few candid=
ates. Here are some potential alternatives:</p><pre>{ explicit ... } //Keyw=
ord makes it clear what's going on.
{, ...} //Comma at the start would normally be illegal.
{| ...}
</pre><p>We could in theory use any operator that only has a binary operati=
on mode. The use
of <span>=93<span>^</span>=94</span> could interfere with C=
++/CX and other similar library
extensions, so <span>=93<span>|</span>=94</span> or some ot=
her operator would be acceptable.</p><p>The operator should probably be wit=
hin the braces, as this makes it more explicit
which is being used.</p></div><div title=3D"Library vs Lang=
uage"><div><div><div><h3><a name=3D"CAKXPfp2GC-JZpVr_77Dc32EcFXwy5hjMHB5CNr=
-7g2n4dyf_mQ@mail.gmail.com_13bedca674f9352c_d0e229"></a>Library vs Languag=
e</h3></div></div></div><p>Originally, I considered a library-based solutio=
n to the issue. This would have
required adding a special opaque type taken as a parameter =
to various calls. Since
the opaque type is different from other types, it would pre=
vent the braced-init-list
from binding to an <span>initializer_list</span> constructo=
r, thus disambiguating
the call.</p><p>This is problematic for two reasons. First,=
it adds some complexity to various
container classes, as they have to prevent the user from us=
ing the opaque type as
the member or allocator types. But the primary reason that =
this is not a good
solution is because it only solves the problem for the stan=
dard library.</p><p>We should not ask every user who writes an <span>initia=
lizer_list</span>
constructor to go though and add a suffix parameter to vari=
ous functions. This is a
problem introduced by the language, and it is best solved i=
n the language.</p></div><div title=3D"Alternate Designs"><div><div><div><h=
3><a name=3D"CAKXPfp2GC-JZpVr_77Dc32EcFXwy5hjMHB5CNr-7g2n4dyf_mQ@mail.gmail=
..com_13bedca674f9352c_d0e244"></a>Alternate Designs</h3></div></div>
</div><p>constr-braced-init-list, in the current design, is intended to wor=
k exactly like
braced-init-list except for which constructors hide which. =
That is, it could still
access <span>initializer_list</span> constructors.</p><p>We=
don't have to do that. There are two other alternatives. We could make
constr-braced-init-list <span><i>never</i></span> use initi=
alizer list
constructors. This would be more uniform in some respects:<=
/p><pre>vector<int> v1{20}; //Creates an array of 1 item.
vector<int> v2{^20}; //Creates an array of 20 items.
vector<int> v3{20, 30, 40}; //Creates an array of 3 items.
vector<int> v4{^20, 30, 40}; //Creates an array of 3 items.</pre><p>T=
he oddball here is <code>v2</code>, which calls a constructor. It would be
more uniform to require this:</p><pre>vector<int> v1{=
{^20}}; //Creates an array of 1 item.
vector<int> v2{^20}; //Creates an array of 20 items.
vector<int> v1{^{20, 30, 40}}; //Creates an array of 3 items.
vector<int> v1{^20, 30, 40}; //Compiler error; no appropriate constru=
ctor to call.</pre><p>The question then becomes whether constr-braced-init-=
list should retain the
<span><i>other</i></span> similarities to regular brace=
d-init-lists. Should
this be allowed:</p><pre>array<int, 3> a1{^10, 20, 30=
};</pre><p>That is, do we want to forbid constr-braced-init-lists from init=
ializing with
anything other than non-initializer_list constructors?</p><=
p>I would say no, and here is why.</p><p>Currently, <code>std::allocator_tr=
aits::<wbr>construct</code> is defined in
terms of calling <code>new(/*stuff*/)
T(std::forward<Args>(args)...)</code><wbr>. That will=
call constructors, but it
will <span><i>only</i></span> call constructors. If we have=
a simple struct that
could use aggregate initialization, we cannot use, for exam=
ple,
<code>emplace</code> on it:</p><pre>struct Agg {int fir=
st, int second};
std::vector<Agg> ag{{10, 20}, {20, 30}, {30, 40}}; //Aggregate initia=
lization is OK here.
ag.emplace_back(10, 20); //Error: no aggregate initialization is possible.<=
/pre><p>There is no reason why we shouldn't be able to do this. To have thi=
s, we would
need to be able to have std::allocator_traits::<wbr>constru=
ct use uniform initialization
syntax: <code>new(/*stuff*/) T{std::forward<Args>(arg=
s)...}</code><wbr>.
However, this can hide constructors;
<code>vector<vector<int>>::emplace_<wbr>bac=
k(10)</code> will add a vector
containing one element. This will break existing applicatio=
ns, not to mention make
it completely impossible to access the hidden constructors =
via
<code>emplace</code>.</p><p>By defining constr-braced-i=
nit-lists as being exactly equal to braced-init-list
except for which constructors it prefers, it makes it possi=
ble to redefine
<code>std::allocator_traits::<wbr>construct</code> in t=
erms of
<code>constr-braced-init-lists</code>. This now means t=
hat the
<code>emplace</code> calls can access aggregate initial=
ization if the
type supports it.</p></div><div title=3D"Change the Definit=
ion"><div><div><div><h3><a name=3D"CAKXPfp2GC-JZpVr_77Dc32EcFXwy5hjMHB5CNr-=
7g2n4dyf_mQ@mail.gmail.com_13bedca674f9352c_d0e315"></a>Change the Definiti=
on</h3></div></div></div><p>There was an alternate design to resolve the is=
sue. Simply declare that
non-<span>initializer_list</span> constructors have pri=
ority, instead of the
other way around. This would make these completely unambigu=
ous:</p><pre>std::vector<int> v1{20};
std::vector<int> v2{{20}};</pre><p><span>v1</span> is using the <span=
>size_type</span> constructor. <span>v2</span>
is clearly calling a single-argument constructor using a br=
aced-init-list.</p><p>The obvious problem with this is that it is a breakin=
g change and a
<span><i>silent</i></span> one at that.</p><p>Even wors=
e, it doesn't look uniform:</p><pre>std::array<int, 6> a1 =3D {1, 2, =
3, 4, 5, 6}; //Brace elision removes the extra pair.
std::vector<int> v1 =3D {1, 2, 3, 4, 5, 6}; //Brace "elision" possibl=
e.
std::array<int, 1> a2 =3D {1}; //Brace elision still works.
std::vector<int> v2 =3D {1}; //Brace "elision" no longer possible d=
ue to conflict. Does the wrong thing.</pre><p>Honestly, this would be the p=
referable solution, if it were not a breaking change.
But it is, so we probably shouldn't do it.</p></div></div><=
span><font color=3D"#888888">
<p></p>
-- <br>
<br>
<br>
<br></font></span></blockquote><div><br></div><div><div>Hi Nicolas,</=
div><div><br></div><div>I think your proposal combined with "Named Argument=
s" (I can not find the paper) could be useful.</div><div><br></div>
<div>I don't know the details of the "Named Arguments" proposal, but, from =
Bjarne's "The Design and Evolution of C++" Section 6.5.1:</div><div>"Roland=
Hartinger's proposal for keyword arguments, that is, for a</div>
<div>mechanism for specifying arguments by name in a call, was close to</di=
v><div>technically perfect. The reason the proposal was withdrawn rather th=
an</div><div>accepted is therefore particularly interesting. ..."</div>
<div><br></div><div><br></div><div>Without having analyzed in depth, I imag=
ine something like this:</div><div><br></div><div>vector<int> v1{20};=
//Creates an array of 1 item.</d=
iv><div>vector<int> v2{ count :=3D 20 }; //Creates an array of =
20 items.</div>
<div>vector<int> v3{20, 30, 40}; //Creates an array of =
3 items.</div><div><br></div><div><br></div><div>I think this syntax is cle=
arer, less ugly and also gives us an excuse to incorporate "Named Arguments=
" into the language.</div></div></div></div></div></blockquote><div><br>Exc=
ept that it doesn't really solve the actual problem in question. Observe:<b=
r><br><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 2=
50); border-color: rgb(187, 187, 187); border-style: solid; border-width: 1=
px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subpr=
ettyprint"><span style=3D"color: #000;" class=3D"styled-by-prettify">vector=
</span><span style=3D"color: #080;" class=3D"styled-by-prettify"><int>=
;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> v1</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span st=
yle=3D"color: #066;" class=3D"styled-by-prettify">20</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">};</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify">  =
; </span><span style=3D"color: #800;" class=3D"styled-by-prettify">//Create=
s an array of 1 item.</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"><br>vector</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify"><</span><span style=3D"color: #606;" class=3D"styled-by-prett=
ify">Type</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&=
gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> v1</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span =
style=3D"color: #066;" class=3D"styled-by-prettify">20</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">};</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> &nb=
sp;</span><span style=3D"color: #800;" class=3D"styled-by-prettify">//Creat=
es an array 20 Types.</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"><br></span></div></code></div><br>If you used {l:} instead:<br><=
br><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250)=
; border-color: rgb(187, 187, 187); border-style: solid; border-width: 1px;=
word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprett=
yprint"><span style=3D"color: #000;" class=3D"styled-by-prettify">vector</s=
pan><span style=3D"color: #080;" class=3D"styled-by-prettify"><int></=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> v1</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">l</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">:</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"=
styled-by-prettify">20</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">};</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> </span><span style=3D"color: #800;" class=
=3D"styled-by-prettify">//Creates an array of 1 item.</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"><br>vector</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify"><</span><span style=3D"color:=
#606;" class=3D"styled-by-prettify">Type</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">></span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> v1</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify">l</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
:</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><=
span style=3D"color: #066;" class=3D"styled-by-prettify">20</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">};</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #800;" class=3D"styled-by-prettify">//Compiler error=
; no matching initializer_list constructor</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br></span></div></code></div><br>Then you =
get a proper compiler error. The person doing the initialization has the ab=
ility to explicitly state what they want to call and what they don't.<br><b=
r>Also, how does that work with aggregate initialization? Does it cause the=
initialization of a particular named field of the aggregate?<br><br>Plus, =
there's the general issue with named parameters at all, which is a very for=
eign concept to C++ in general. The idea of a template's concept requiring =
a parameter name is very... disconcerting.<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_390_26361578.1357594500476--
.
Author: Fernando Pelliccioni <fpelliccioni@gmail.com>
Date: Tue, 8 Jan 2013 02:17:56 -0300
Raw View
--20cf303349618b80c504d2c011c5
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Mon, Jan 7, 2013 at 6:35 PM, Nicol Bolas <jmckesson@gmail.com> wrote:
>
>
> On Monday, January 7, 2013 5:15:29 AM UTC-8, Fernando Pelliccioni wrote:
>
>> On Sun, Dec 30, 2012 at 6:49 PM, Nicol Bolas <jmck...@gmail.com> wrote:
>>
>>> What follows is a draft of a proposal for adding new rules for uniform
>>> initialization syntax. It covers what it wants pretty well, so I'll let=
it
>>> speak for itself.
>>>
>>> Introduction
>>>
>>> Braced-init-lists were originally used in object initialization with
>>> aggregate initialization. In the development of C++11, the idea was
>>> extended to include non-aggregate types through the use of a special
>>> initializer_list type.
>>>
>>> This idea was ultimately extended into what became known as uniform
>>> initialization: one could initially any type via the use of a
>>> braced-init-list. Doing so provides a number of advantages, among them =
is
>>> uniform initialization behavior and the elimination of the most vexing
>>> parse. In a perfect world, we would always use uniform initialization a=
nd
>>> never use direct constructor syntax.
>>>
>>> However, despite being called =93uniform initialization,=94 it cannot b=
e
>>> uniformly used everywhere, due to a critical flaw that prevents its use
>>> towards these ends. This proposal intends to correct this flaw, thus
>>> allowing it to be used in all possible cases of object construction, wh=
ile
>>> having well-defined results.
>>> Motivation and Scope
>>>
>>> The flaw in uniform initialization is quite simple to see in the
>>> standard library. The std::vector type has an explicit constructor
>>> which takes a single std::vector::size_type, which is an integral type.
>>> std::vector also has a constructor that takes an initializer_list<T>.
>>>
>>> For most types, these constructors can coexist with uniform
>>> initialization quite reasonably. For example:
>>>
>>> std::vector<A> v1{20};
>>> std::vector<A> v2{A{}};
>>> std::vector<A> v3{A{}, A{}, A{}};
>>>
>>> In this example, v1 is an array of 20 value-constructed values. v2 is
>>> an array of 1 value-constructed element. v3 is an array of 3
>>> value-constructed elements.
>>>
>>> This is all well and good, until we do this:
>>>
>>> std::vector<int> v1{20};
>>> std::vector<int> v2{int{}};
>>> std::vector<int> v3{int{}, int{}, int{}};
>>>
>>> v2 and v3 retain their old meaning. But v1 is now very different. It is
>>> an array containing a single element, the number 20. Why?
>>>
>>> Because uniform initialization syntax always prefers initializer list
>>> constructors if one is available that would fit the braced-init-list. T=
his
>>> is a consequence of uniform initialization syntax using the same syntax=
as
>>> initializer lists: the braced-init-list. And since
>>> std::vector<int>::vector(std::**initializer_list<int>) matches the
>>> braced-init-list ({20}), it will be preferred over
>>> std::vector<int>::vector(std::**vector<int>::size_type)
>>>
>>> This is a problem because there is *no way* to get at the size_typecons=
tructor via uniform initialization. There is no syntax that we can
>>> employ which will cause the conflicting initializer_list constructor to
>>> be ignored or to do anything else that would allow us to get at a diffe=
rent
>>> set of constructors.
>>>
>>> Now, this may seem like a rather unimportant issue. After all, if I kno=
w
>>> that I have to use constructor initialization with vector<int>, then I
>>> can simply do that. But consider code that is generic on the vector's
>>> type:
>>>
>>> template<typename T>
>>> std::vector<T> MakeVector()
>>> {
>>> return std::vector<T>{20};
>>> }
>>>
>>> By all rights, this code should always do the same thing: return a
>>> vector containing 20 value-initialized elements. But it does not.
>>> MakeVector<int>() will return a vector containing exactly one element.
>>>
>>> This is of much greater concern when dealing with more intricate
>>> templates. Consider the following trivial template function:
>>>
>>> template<typename T>
>>> T Process()
>>> {
>>> T t{};
>>> //do stuff with t;
>>> return T{t};
>>> }
>>>
>>> This function creates a temporary, does some processing, and returns a
>>> copy of it. This function requires that T be DefaultConstructible and
>>> CopyConstructible, in addition to whatever =93do stuff with t=94 requir=
es.
>>>
>>> The problem is the last line. This line *may* violate the concept
>>> constraint. Why? Because there is no guarantee that T does *not* have
>>> an initializer_list constructor that can match with a T. For an example
>>> of such a class, consider std::vector<std::function<**void()>> as our T=
..
>>>
>>> The problem is that std::function has a non-explicit constructor that
>>> can take *any* type that is CopyConstructible. And
>>> std::vector<std::function> is CopyConstructible. Therefore, this will
>>> call the initializer_list constructor. But the template function should=
not
>>> be calling the initializer list constructor; it's not part of the allow=
ed
>>> interface to T. Therefore, Process violates the concept constraint,
>>> through no fault on the user's part.
>>>
>>> What this means is that you cannot use uniform initialization in generi=
c
>>> code where the exact type of the object being constructed is derived fr=
om a
>>> template parameter. This is because there is no way for the user to
>>> explicitly choose which constructors to call.
>>> Design Overview
>>>
>>> The idea is quite simple. We will divide braced-init-list up into two
>>> variation: list-braced-init-list and constr-braced-init-list. Most of t=
he
>>> text will remain the exact same, as they have almost identical behavior=
..
>>>
>>> The difference is that 13.3.1.7's list initialization overload
>>> resolution rules will behave differently. list-braced-init-list
>>> initialization will work exactly as it does. constr-braced-init-list wi=
ll
>>> work opposite to the current way. That is, it will check
>>> non-initializer_list constructors first, then go to the initializer_lis=
t
>>> ones if no matching constructors are found. All other uses will work
>>> identically; you can use these for aggregate initialization and so fort=
h
>>> just as before.
>>>
>>> The big issue is how constr-braced-init-lists are defined in the
>>> grammar. It should look like this:
>>>
>>> {^ ... }
>>>
>>> The =93{=94 token followed by the =93^=94 token is what distinguishes t=
he
>>> constr-braced-init-list from a list-braced-init-list.
>>> Note
>>>
>>> I have no particular love for the use of =93^=94 here. My reasons for i=
ts
>>> selection are listed in the Grammar section of the Design Discussions
>>> segment of the document.
>>> Impact on the Standard
>>>
>>> Depending on how we want to handle the wording, we may need a new set o=
f
>>> =93list-initialization=94 types. 13.3.1.7 never mentions braced-init-li=
st;
>>> it only operates in terms of list-initialization, which stems from a
>>> specific use of braced-init-list. We could have it say something like =
=93if
>>> the braced-init-list that issues this constructor is a
>>> list-braced-init-list, then ...=94 Or we could provide different forms =
of
>>> =93list-initialization.=94
>>>
>>> It should cause zero backwards compatibility problems.
>>> list-braced-init-lists should have the same behavior as before. Also, s=
ee
>>> the Design Decisions section, the Grammar part.
>>> Design Decisions
>>> Bikeshedding
>>>
>>> Finding the right grammar for this will likely be the biggest stumbling
>>> point. I would say that the most important metrics for a good piece of
>>> grammar are:
>>>
>>> -
>>>
>>> Backwards compatibility. Whatever grammar we use, it should be
>>> something that would have been illegal in C++11, no matter what lite=
rals,
>>> identifiers, and tokens come after it.
>>> -
>>>
>>> Brevity. It should be used a lot, so it shouldn't take up a lot of
>>> space.
>>>
>>> This leaves few candidates. Here are some potential alternatives:
>>>
>>> { explicit ... } //Keyword makes it clear what's going on.
>>> {, ...} //Comma at the start would normally be illegal.
>>> {| ...}
>>>
>>> We could in theory use any operator that only has a binary operation
>>> mode. The use of =93^=94 could interfere with C++/CX and other similar
>>> library extensions, so =93|=94 or some other operator would be acceptab=
le.
>>>
>>> The operator should probably be within the braces, as this makes it mor=
e
>>> explicit which is being used.
>>> Library vs Language
>>>
>>> Originally, I considered a library-based solution to the issue. This
>>> would have required adding a special opaque type taken as a parameter t=
o
>>> various calls. Since the opaque type is different from other types, it
>>> would prevent the braced-init-list from binding to an initializer_listc=
onstructor, thus disambiguating the call.
>>>
>>> This is problematic for two reasons. First, it adds some complexity to
>>> various container classes, as they have to prevent the user from using =
the
>>> opaque type as the member or allocator types. But the primary reason th=
at
>>> this is not a good solution is because it only solves the problem for t=
he
>>> standard library.
>>>
>>> We should not ask every user who writes an initializer_list constructor
>>> to go though and add a suffix parameter to various functions. This is a
>>> problem introduced by the language, and it is best solved in the langua=
ge.
>>> Alternate Designs
>>>
>>> constr-braced-init-list, in the current design, is intended to work
>>> exactly like braced-init-list except for which constructors hide which.
>>> That is, it could still access initializer_list constructors.
>>>
>>> We don't have to do that. There are two other alternatives. We could
>>> make constr-braced-init-list *never* use initializer list constructors.
>>> This would be more uniform in some respects:
>>>
>>> vector<int> v1{20}; //Creates an array of 1 item.
>>> vector<int> v2{^20}; //Creates an array of 20 items.
>>> vector<int> v3{20, 30, 40}; //Creates an array of 3 items.
>>> vector<int> v4{^20, 30, 40}; //Creates an array of 3 items.
>>>
>>> The oddball here is v2, which calls a constructor. It would be more
>>> uniform to require this:
>>>
>>> vector<int> v1{{^20}}; //Creates an array of 1 item.
>>> vector<int> v2{^20}; //Creates an array of 20 items.
>>> vector<int> v1{^{20, 30, 40}}; //Creates an array of 3 items.
>>> vector<int> v1{^20, 30, 40}; //Compiler error; no appropriate construct=
or to call.
>>>
>>> The question then becomes whether constr-braced-init-list should retain
>>> the *other* similarities to regular braced-init-lists. Should this be
>>> allowed:
>>>
>>> array<int, 3> a1{^10, 20, 30};
>>>
>>> That is, do we want to forbid constr-braced-init-lists from initializin=
g
>>> with anything other than non-initializer_list constructors?
>>>
>>> I would say no, and here is why.
>>>
>>> Currently, std::allocator_traits::**construct is defined in terms of
>>> calling new(/*stuff*/) T(std::forward<Args>(args)...)**. That will call
>>> constructors, but it will *only* call constructors. If we have a simple
>>> struct that could use aggregate initialization, we cannot use, for exam=
ple,
>>> emplace on it:
>>>
>>> struct Agg {int first, int second};
>>>
>>> std::vector<Agg> ag{{10, 20}, {20, 30}, {30, 40}}; //Aggregate initiali=
zation is OK here.
>>> ag.emplace_back(10, 20); //Error: no aggregate initialization is possib=
le.
>>>
>>> There is no reason why we shouldn't be able to do this. To have this, w=
e
>>> would need to be able to have std::allocator_traits::**construct use
>>> uniform initialization syntax: new(/*stuff*/)
>>> T{std::forward<Args>(args)...}**. However, this can hide constructors;
>>> vector<vector<int>>::emplace_**back(10) will add a vector containing
>>> one element. This will break existing applications, not to mention make=
it
>>> completely impossible to access the hidden constructors via emplace.
>>>
>>> By defining constr-braced-init-lists as being exactly equal to
>>> braced-init-list except for which constructors it prefers, it makes it
>>> possible to redefine std::allocator_traits::**construct in terms of
>>> constr-braced-init-lists. This now means that the emplace calls can
>>> access aggregate initialization if the type supports it.
>>> Change the Definition
>>>
>>> There was an alternate design to resolve the issue. Simply declare that
>>> non-initializer_list constructors have priority, instead of the other
>>> way around. This would make these completely unambiguous:
>>>
>>> std::vector<int> v1{20};
>>> std::vector<int> v2{{20}};
>>>
>>> v1 is using the size_type constructor. v2 is clearly calling a
>>> single-argument constructor using a braced-init-list.
>>>
>>> The obvious problem with this is that it is a breaking change and a *
>>> silent* one at that.
>>>
>>> Even worse, it doesn't look uniform:
>>>
>>> std::array<int, 6> a1 =3D {1, 2, 3, 4, 5, 6}; //Brace elision removes t=
he extra pair.
>>> std::vector<int> v1 =3D {1, 2, 3, 4, 5, 6}; //Brace "elision" possible.
>>> std::array<int, 1> a2 =3D {1}; //Brace elision still works.
>>> std::vector<int> v2 =3D {1}; //Brace "elision" no longer possible due=
to conflict. Does the wrong thing.
>>>
>>> Honestly, this would be the preferable solution, if it were not a
>>> breaking change. But it is, so we probably shouldn't do it.
>>>
>>> --
>>>
>>>
>>>
>>>
>>
>> Hi Nicolas,
>>
>> I think your proposal combined with "Named Arguments" (I can not find th=
e
>> paper) could be useful.
>>
>> I don't know the details of the "Named Arguments" proposal, but, from
>> Bjarne's "The Design and Evolution of C++" Section 6.5.1:
>> "Roland Hartinger's proposal for keyword arguments, that is, for a
>> mechanism for specifying arguments by name in a call, was close to
>> technically perfect. The reason the proposal was withdrawn rather than
>> accepted is therefore particularly interesting. ..."
>>
>>
>> Without having analyzed in depth, I imagine something like this:
>>
>> vector<int> v1{20}; //Creates an array of 1 item.
>> vector<int> v2{ count :=3D 20 }; //Creates an array of 20 items.
>> vector<int> v3{20, 30, 40}; //Creates an array of 3 items.
>>
>>
>> I think this syntax is clearer, less ugly and also gives us an excuse to
>> incorporate "Named Arguments" into the language.
>>
>
> Except that it doesn't really solve the actual problem in question.
> Observe:
>
> vector<int> v1{20}; //Creates an array of 1 item.
>
> vector<Type> v1{20}; //Creates an array 20 Types.
>
>
Perfect, like C++11
> If you used {l:} instead:
>
> vector<int> v1{l: 20}; //Creates an array of 1 item.
> vector<Type> v1{l: 20}; //Compiler error; no matching
> initializer_list constructor
>
>
What is supposed to be "l:" ?
Is the name of a constructor parameter ?
> Then you get a proper compiler error. The person doing the initialization
> has the ability to explicitly state what they want to call and what they
> don't.
>
>
I don't understand what the point of this example.
> Also, how does that work with aggregate initialization? Does it cause the
> initialization of a particular named field of the aggregate?
>
>
I think it does not apply in this case.
How does your proposal work with aggregate initialization?
> Plus, there's the general issue with named parameters at all, which is a
> very foreign concept to C++ in general.
>
"foreign concept to C++" not disqualify its usefulness.
It is a common concept, like many other additions to C++ that have come
from other languages.
> The idea of a template's concept requiring a parameter name is very...
> disconcerting.
>
>
>
I would like to access the original proposal to view it in detail.
Regards,
--=20
--20cf303349618b80c504d2c011c5
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><div class=3D"gmail_extra"><br><br><div class=3D"gmail=
_quote">On Mon, Jan 7, 2013 at 6:35 PM, Nicol Bolas <span dir=3D"ltr"><<=
a href=3D"mailto:jmckesson@gmail.com" target=3D"_blank">jmckesson@gmail.com=
</a>></span> wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-=
left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p=
adding-left:1ex"><br><br>On Monday, January 7, 2013 5:15:29 AM UTC-8, Ferna=
ndo Pelliccioni wrote:<div>
<div class=3D"h5"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px=
0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-=
left-style:solid;padding-left:1ex"><div dir=3D"ltr"><div><div class=3D"gmai=
l_quote">
On Sun, Dec 30, 2012 at 6:49 PM, Nicol Bolas <span dir=3D"ltr"><<a>jmck.=
...@gmail.com</a>></span> wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-=
left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p=
adding-left:1ex">What follows is a draft of a proposal for adding new rules=
for uniform initialization syntax. It covers what it wants pretty well, so=
I'll let it speak for itself.<br>
<br><div title=3D"Introduction"><div><div><div><h2 style=3D"clear:both"><a =
name=3D"13c16f023161340c_CAKXPfp2GC-JZpVr_77Dc32EcFXwy5hjMHB5CNr-7g2n4dyf_m=
Q@mail.gmail.com_13bedca674f9352c_d0e6"></a>Introduction</h2></div></div></=
div>
<p>Braced-init-lists were originally used in object initialization with agg=
regate
initialization. In the development of C++11, the idea was exten=
ded to include
non-aggregate types through the use of a special <span>initiali=
zer_list</span>
type.</p><p>This idea was ultimately extended into what became =
known as uniform initialization:
one could initially any type via the use of a braced-init-list.=
Doing so provides a
number of advantages, among them is uniform initialization beha=
vior and the elimination
of the most vexing parse. In a perfect world, we would always u=
se uniform initialization
and never use direct constructor syntax.</p><p>However, despite=
being called <span>=93<span>uniform initialization,</span>=94</span> it ca=
nnot be
uniformly used everywhere, due to a critical flaw that prevents=
its use towards these
ends. This proposal intends to correct this flaw, thus allowing=
it to be used in all
possible cases of object construction, while having well-define=
d results.</p></div><div title=3D"Motivation and Scope"><div><div><div><h2 =
style=3D"clear:both"><a name=3D"13c16f023161340c_CAKXPfp2GC-JZpVr_77Dc32EcF=
Xwy5hjMHB5CNr-7g2n4dyf_mQ@mail.gmail.com_13bedca674f9352c_d0e21"></a>Motiva=
tion and Scope</h2>
</div></div></div><p>The flaw in uniform initialization is quite simple to =
see in the standard library. The
<span>std::vector</span> type has an explicit constructor w=
hich takes a single
<span>std::vector::size_type</span>, which is an integral t=
ype.
<span>std::vector</span> also has a constructor that takes =
an
<span>initializer_list<T></span>.</p><p>For most type=
s, these constructors can coexist with uniform initialization quite
reasonably. For example:</p><pre>std::vector<A> v1{20};
std::vector<A> v2{A{}};
std::vector<A> v3{A{}, A{}, A{}};</pre><p>In this example, <code>v1</=
code> is an array of 20 value-constructed values.
<code>v2</code> is an array of 1 value-constructed element.
<code>v3</code> is an array of 3 value-constructed elements=
..</p><p>This is all well and good, until we do this:</p><pre>std::vector<=
;int> v1{20};
std::vector<int> v2{int{}};
std::vector<int> v3{int{}, int{}, int{}};</pre><p><code>v2</code> and=
<code>v3</code> retain their old meaning. But
<code>v1</code> is now very different. It is an array conta=
ining a single
element, the number 20. Why?</p><p>Because uniform initializati=
on syntax always prefers initializer list constructors if
one is available that would fit the braced-init-list. This is a=
consequence of uniform
initialization syntax using the same syntax as initializer list=
s: the braced-init-list.
And since
<code>std::vector<int>::vector(std::<u></u>initialize=
r_list<int>)</code>
matches the braced-init-list (<code>{20}</code>), it will be pr=
eferred over
<code>std::vector<int>::vector(std::<u></u>vector<=
int>::size_type)</code></p><p>This is a problem because there is <span><=
i>no way</i></span> to get at the
<span>size_type</span> constructor via uniform initializati=
on. There is no syntax
that we can employ which will cause the conflicting <span>initi=
alizer_list</span>
constructor to be ignored or to do anything else that would all=
ow us to get at a
different set of constructors.</p><p>Now, this may seem like a =
rather unimportant issue. After all, if I know that I have
to use constructor initialization with <span>vector<int><=
/span>, then I can simply do
that. But consider code that is generic on the <span>vector</sp=
an>'s type:</p><pre>template<typename T>
std::vector<T> MakeVector()
{
return std::vector<T>{20};
}</pre><p>By all rights, this code should always do the same thing: return =
a <span>vector</span>
containing 20 value-initialized elements. But it does not.
<code>MakeVector<int>()</code> will return a <span>ve=
ctor</span>
containing exactly one element.</p><p>This is of much greater c=
oncern when dealing with more intricate templates. Consider
the following trivial template function:</p><pre>template<ty=
pename T>
T Process()
{
T t{};
//do stuff with t;
return T{t};
}</pre><p>This function creates a temporary, does some processing, and retu=
rns a copy of it.
This function requires that <span>T</span> be DefaultConstructi=
ble and
CopyConstructible, in addition to whatever <span>=93<span>do st=
uff with t</span>=94</span>
requires.</p><p>The problem is the last line. This line <span><=
i>may</i></span> violate the concept
constraint. Why? Because there is no guarantee that <span>T</sp=
an> does
<span><i>not</i></span> have an <span>initializer_list</spa=
n> constructor that can
match with a <span>T</span>. For an example of such a class, co=
nsider
<span>std::vector<std::function<<u></u>void()>>=
</span> as our <span>T</span>.</p><p>The problem is that <span>std::functio=
n</span> has a non-explicit constructor that can
take <span><i>any</i></span> type that is CopyConstructible. An=
d
<span>std::vector<std::function></span> is CopyConstr=
uctible. Therefore, this
will call the initializer_list constructor. But the template fu=
nction should not be
calling the initializer list constructor; it's not part of =
the allowed interface to T.
Therefore, <code>Process</code> violates the concept constraint=
, through no
fault on the user's part.</p><p>What this means is that you=
cannot use uniform initialization in generic code where
the exact type of the object being constructed is derived from =
a template parameter.
This is because there is no way for the user to explicitly choo=
se which constructors to
call.</p></div><div title=3D"Design Overview"><div><div><div><h=
2 style=3D"clear:both"><a name=3D"13c16f023161340c_CAKXPfp2GC-JZpVr_77Dc32E=
cFXwy5hjMHB5CNr-7g2n4dyf_mQ@mail.gmail.com_13bedca674f9352c_d0e160"></a>Des=
ign Overview</h2>
</div></div></div><p>The idea is quite simple. We will divide braced-init-l=
ist up into two variation:
list-braced-init-list and constr-braced-init-list. Most of the =
text will remain the
exact same, as they have almost identical behavior.</p><p>The d=
ifference is that 13.3.1.7's list initialization overload resolution ru=
les will
behave differently. list-braced-init-list initialization will w=
ork exactly as it does.
constr-braced-init-list will work opposite to the current way. =
That is, it will check
non-initializer_list constructors first, then go to the initial=
izer_list ones if no
matching constructors are found. All other uses will work ident=
ically; you can use these
for aggregate initialization and so forth just as before.</p><p=
>The big issue is how constr-braced-init-lists are defined in the grammar. =
It should
look like this:</p><pre>{^ ... }</pre><p>The <span>=93<span>{</=
span>=94</span> token followed by the <span>=93<span>^</span>=94</span> tok=
en is what
distinguishes the constr-braced-init-list from a list-braced-in=
it-list.</p><div title=3D"Note" style=3D"margin-left:0.5in;margin-right:0.5=
in"><h3>Note</h3><p>I have no particular love for the use of <span>=93<span=
>^</span>=94</span> here. My reasons for its
selection are listed in the Grammar section of the Design D=
iscussions segment of the
document.</p></div></div><div title=3D"Impact on the Standa=
rd"><div><div><div><h2 style=3D"clear:both"><a name=3D"13c16f023161340c_CAK=
XPfp2GC-JZpVr_77Dc32EcFXwy5hjMHB5CNr-7g2n4dyf_mQ@mail.gmail.com_13bedca674f=
9352c_d0e185"></a>Impact on the Standard</h2>
</div></div></div><p>Depending on how we want to handle the wording, we may=
need a new set of
<span>=93<span>list-initialization</span>=94</span> types. =
13.3.1.7 never mentions braced-init-list;
it only operates in terms of list-initialization, which stems f=
rom a specific use of
braced-init-list. We could have it say something like <span>=93=
<span>if the braced-init-list
that issues this constructor is a list-braced-init-list, th=
en ...</span>=94</span> Or we
could provide different forms of <span>=93<span>list-initializa=
tion.</span>=94</span></p><p>It should cause zero backwards compatibility p=
roblems. list-braced-init-lists should
have the same behavior as before. Also, see the Design Decision=
s section, the Grammar
part.</p></div><div title=3D"Design Decisions"><div><div><div><=
h2 style=3D"clear:both"><a name=3D"13c16f023161340c_CAKXPfp2GC-JZpVr_77Dc32=
EcFXwy5hjMHB5CNr-7g2n4dyf_mQ@mail.gmail.com_13bedca674f9352c_d0e200"></a>De=
sign Decisions</h2>
</div></div></div><div title=3D"Bikeshedding"><div><div><div><h3><a name=3D=
"13c16f023161340c_CAKXPfp2GC-JZpVr_77Dc32EcFXwy5hjMHB5CNr-7g2n4dyf_mQ@mail.=
gmail.com_13bedca674f9352c_d0e203"></a>Bikeshedding</h3>
</div></div></div><p>Finding the right grammar for this will likely be the =
biggest stumbling point. I
would say that the most important metrics for a good piece =
of grammar are:</p><div><ul type=3D"disc"><li><p>Backwards compatibility. W=
hatever grammar we use, it should be something
that would have been illegal in C++11, no matter wh=
at literals, identifiers,
and tokens come after it.</p></li><li><p>Brevity. I=
t should be used a lot, so it shouldn't take up a lot of
space.</p></li></ul></div><p>This leaves few candid=
ates. Here are some potential alternatives:</p><pre>{ explicit ... } //Keyw=
ord makes it clear what's going on.
{, ...} //Comma at the start would normally be illegal.
{| ...}
</pre><p>We could in theory use any operator that only has a binary operati=
on mode. The use
of <span>=93<span>^</span>=94</span> could interfere with C=
++/CX and other similar library
extensions, so <span>=93<span>|</span>=94</span> or some ot=
her operator would be acceptable.</p><p>The operator should probably be wit=
hin the braces, as this makes it more explicit
which is being used.</p></div><div title=3D"Library vs Lang=
uage"><div><div><div><h3><a name=3D"13c16f023161340c_CAKXPfp2GC-JZpVr_77Dc3=
2EcFXwy5hjMHB5CNr-7g2n4dyf_mQ@mail.gmail.com_13bedca674f9352c_d0e229"></a>L=
ibrary vs Language</h3>
</div></div></div><p>Originally, I considered a library-based solution to t=
he issue. This would have
required adding a special opaque type taken as a parameter =
to various calls. Since
the opaque type is different from other types, it would pre=
vent the braced-init-list
from binding to an <span>initializer_list</span> constructo=
r, thus disambiguating
the call.</p><p>This is problematic for two reasons. First,=
it adds some complexity to various
container classes, as they have to prevent the user from us=
ing the opaque type as
the member or allocator types. But the primary reason that =
this is not a good
solution is because it only solves the problem for the stan=
dard library.</p><p>We should not ask every user who writes an <span>initia=
lizer_list</span>
constructor to go though and add a suffix parameter to vari=
ous functions. This is a
problem introduced by the language, and it is best solved i=
n the language.</p></div><div title=3D"Alternate Designs"><div><div><div><h=
3><a name=3D"13c16f023161340c_CAKXPfp2GC-JZpVr_77Dc32EcFXwy5hjMHB5CNr-7g2n4=
dyf_mQ@mail.gmail.com_13bedca674f9352c_d0e244"></a>Alternate Designs</h3>
</div></div>
</div><p>constr-braced-init-list, in the current design, is intended to wor=
k exactly like
braced-init-list except for which constructors hide which. =
That is, it could still
access <span>initializer_list</span> constructors.</p><p>We=
don't have to do that. There are two other alternatives. We could make
constr-braced-init-list <span><i>never</i></span> use initi=
alizer list
constructors. This would be more uniform in some respects:<=
/p><pre>vector<int> v1{20}; //Creates an array of 1 item.
vector<int> v2{^20}; //Creates an array of 20 items.
vector<int> v3{20, 30, 40}; //Creates an array of 3 items.
vector<int> v4{^20, 30, 40}; //Creates an array of 3 items.</pre><p>T=
he oddball here is <code>v2</code>, which calls a constructor. It would be
more uniform to require this:</p><pre>vector<int> v1{=
{^20}}; //Creates an array of 1 item.
vector<int> v2{^20}; //Creates an array of 20 items.
vector<int> v1{^{20, 30, 40}}; //Creates an array of 3 items.
vector<int> v1{^20, 30, 40}; //Compiler error; no appropriate constru=
ctor to call.</pre><p>The question then becomes whether constr-braced-init-=
list should retain the
<span><i>other</i></span> similarities to regular brace=
d-init-lists. Should
this be allowed:</p><pre>array<int, 3> a1{^10, 20, 30=
};</pre><p>That is, do we want to forbid constr-braced-init-lists from init=
ializing with
anything other than non-initializer_list constructors?</p><=
p>I would say no, and here is why.</p><p>Currently, <code>std::allocator_tr=
aits::<u></u>construct</code> is defined in
terms of calling <code>new(/*stuff*/)
T(std::forward<Args>(args)...)</code><u></u>. That wi=
ll call constructors, but it
will <span><i>only</i></span> call constructors. If we have=
a simple struct that
could use aggregate initialization, we cannot use, for exam=
ple,
<code>emplace</code> on it:</p><pre>struct Agg {int fir=
st, int second};
std::vector<Agg> ag{{10, 20}, {20, 30}, {30, 40}}; //Aggregate initia=
lization is OK here.
ag.emplace_back(10, 20); //Error: no aggregate initialization is possible.<=
/pre><p>There is no reason why we shouldn't be able to do this. To have=
this, we would
need to be able to have std::allocator_traits::<u></u>const=
ruct use uniform initialization
syntax: <code>new(/*stuff*/) T{std::forward<Args>(arg=
s)...}</code><u></u>.
However, this can hide constructors;
<code>vector<vector<int>>::emplace_<u></u>b=
ack(10)</code> will add a vector
containing one element. This will break existing applicatio=
ns, not to mention make
it completely impossible to access the hidden constructors =
via
<code>emplace</code>.</p><p>By defining constr-braced-i=
nit-lists as being exactly equal to braced-init-list
except for which constructors it prefers, it makes it possi=
ble to redefine
<code>std::allocator_traits::<u></u>construct</code> in=
terms of
<code>constr-braced-init-lists</code>. This now means t=
hat the
<code>emplace</code> calls can access aggregate initial=
ization if the
type supports it.</p></div><div title=3D"Change the Definit=
ion"><div><div><div><h3><a name=3D"13c16f023161340c_CAKXPfp2GC-JZpVr_77Dc32=
EcFXwy5hjMHB5CNr-7g2n4dyf_mQ@mail.gmail.com_13bedca674f9352c_d0e315"></a>Ch=
ange the Definition</h3>
</div></div></div><p>There was an alternate design to resolve the issue. Si=
mply declare that
non-<span>initializer_list</span> constructors have pri=
ority, instead of the
other way around. This would make these completely unambigu=
ous:</p><pre>std::vector<int> v1{20};
std::vector<int> v2{{20}};</pre><p><span>v1</span> is using the <span=
>size_type</span> constructor. <span>v2</span>
is clearly calling a single-argument constructor using a br=
aced-init-list.</p><p>The obvious problem with this is that it is a breakin=
g change and a
<span><i>silent</i></span> one at that.</p><p>Even wors=
e, it doesn't look uniform:</p><pre>std::array<int, 6> a1 =3D {1,=
2, 3, 4, 5, 6}; //Brace elision removes the extra pair.
std::vector<int> v1 =3D {1, 2, 3, 4, 5, 6}; //Brace "elision&quo=
t; possible.
std::array<int, 1> a2 =3D {1}; //Brace elision still works.
std::vector<int> v2 =3D {1}; //Brace "elision" no longer =
possible due to conflict. Does the wrong thing.</pre><p>Honestly, this woul=
d be the preferable solution, if it were not a breaking change.
But it is, so we probably shouldn't do it.</p></div></d=
iv><span><font color=3D"#888888">
<p></p>
-- <br>
=A0<br>
=A0<br>
=A0<br></font></span></blockquote><div><br></div><div><div>Hi Nicolas,</div=
><div><br></div><div>I think your proposal combined with "Named Argume=
nts" (I can not find the paper) could be useful.</div><div><br></div>
<div>I don't know the details of the "Named Arguments" propos=
al, but, from Bjarne's "The Design and Evolution of C++" Sect=
ion 6.5.1:</div><div>"Roland Hartinger's proposal for keyword argu=
ments, that is, for a</div>
<div>mechanism for specifying arguments by name in a call, was close to</di=
v><div>technically perfect. The reason the proposal was withdrawn rather th=
an</div><div>accepted is therefore particularly interesting. ..."</div=
>
<div><br></div><div><br></div><div>Without having analyzed in depth, I imag=
ine something like this:</div><div><br></div><div>vector<int> v1{20};=
=A0 =A0 =A0 =A0 =A0 =A0 //Creates an array of 1 item.</div><div>vector<=
int> v2{ count :=3D 20 }; =A0//Creates an array of 20 items.</div>
<div>vector<int> v3{20, 30, 40}; =A0 =A0 //Creates an array of 3 item=
s.</div><div><br></div><div><br></div><div>I think this syntax is clearer, =
less ugly and also gives us an excuse to incorporate "Named Arguments&=
quot; into the language.</div>
</div></div></div></div></blockquote></div></div><div><br>Except that it do=
esn't really solve the actual problem in question. Observe:<br><br><div=
style=3D"background-color:rgb(250,250,250);border:1px solid rgb(187,187,18=
7);word-wrap:break-word">
<code><div><div class=3D"im"><span style>vector</span><span style=3D"color:=
rgb(0,136,0)"><int></span><span style> v1</span><span style=3D"color:=
rgb(102,102,0)">{</span><span style=3D"color:rgb(0,102,102)">20</span><span=
style=3D"color:rgb(102,102,0)">};</span><span style> =A0 =A0 =A0 =A0 =A0 =
=A0 </span><span style=3D"color:rgb(136,0,0)">//Creates an array of 1 item.=
</span></div>
<span style><br>vector</span><span style=3D"color:rgb(102,102,0)"><</spa=
n><span style=3D"color:rgb(102,0,102)">Type</span><span style=3D"color:rgb(=
102,102,0)">></span><span style> v1</span><span style=3D"color:rgb(102,1=
02,0)">{</span><span style=3D"color:rgb(0,102,102)">20</span><span style=3D=
"color:rgb(102,102,0)">};</span><span style> =A0 =A0 =A0 =A0 =A0 =A0</span>=
<span style=3D"color:rgb(136,0,0)">//Creates an array 20 Types.</span><span=
style><br>
</span></div></code></div><br></div></blockquote><div><br></div><div style>=
Perfect, like C++11</div><div>=A0</div><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb=
(204,204,204);border-left-style:solid;padding-left:1ex">
<div>If you used {l:} instead:<br><br><div style=3D"background-color:rgb(25=
0,250,250);border:1px solid rgb(187,187,187);word-wrap:break-word"><code><d=
iv><span style>vector</span><span style=3D"color:rgb(0,136,0)"><int><=
/span><span style> v1</span><span style=3D"color:rgb(102,102,0)">{</span><s=
pan style>l</span><span style=3D"color:rgb(102,102,0)">:</span><span style>=
</span><span style=3D"color:rgb(0,102,102)">20</span><span style=3D"color:=
rgb(102,102,0)">};</span><span style> =A0 =A0 =A0 =A0 </span><span style=3D=
"color:rgb(136,0,0)">//Creates an array of 1 item.</span><span style><br>
vector</span><span style=3D"color:rgb(102,102,0)"><</span><span style=3D=
"color:rgb(102,0,102)">Type</span><span style=3D"color:rgb(102,102,0)">>=
</span><span style> v1</span><span style=3D"color:rgb(102,102,0)">{</span><=
span style>l</span><span style=3D"color:rgb(102,102,0)">:</span><span style=
> </span><span style=3D"color:rgb(0,102,102)">20</span><span style=3D"color=
:rgb(102,102,0)">};</span><span style> =A0 =A0 =A0 =A0</span><span style=3D=
"color:rgb(136,0,0)">//Compiler error; no matching initializer_list constru=
ctor</span><span style><br>
</span></div></code></div><br></div></blockquote><div><br></div><div>What i=
s supposed to be "l:" ?<br></div><div>Is the name of a constructo=
r parameter ?<br></div><div>=A0<br></div><blockquote class=3D"gmail_quote" =
style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:r=
gb(204,204,204);border-left-style:solid;padding-left:1ex">
<div>Then you get a proper compiler error. The person doing the initializat=
ion has the ability to explicitly state what they want to call and what the=
y don't.<br><br></div></blockquote><div><br></div><div>I don't unde=
rstand what the point of this example.<br>
</div><div>=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0=
px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);borde=
r-left-style:solid;padding-left:1ex"><div>Also, how does that work with agg=
regate initialization? Does it cause the initialization of a particular nam=
ed field of the aggregate?<br>
<br></div></blockquote><div><br></div><div>I think it does not apply in thi=
s case.<br></div><div>How does your proposal work with aggregate initializa=
tion?<br></div><div>=A0</div><blockquote class=3D"gmail_quote" style=3D"mar=
gin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,2=
04);border-left-style:solid;padding-left:1ex">
<div>Plus, there's the general issue with named parameters at all, whic=
h is a very foreign concept to C++ in general.</div></blockquote><div><br><=
/div><div>"foreign concept to C++" not disqualify its usefulness.=
</div>
<div>It is a common concept, like many other=A0additions to C++ that have c=
ome from=A0other languages.=A0</div><div>=A0<br></div><blockquote class=3D"=
gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border=
-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div> The idea of a template's concept requiring a parameter name is ve=
ry... disconcerting.<span class=3D""><font color=3D"#888888"><br></font></s=
pan></div><span class=3D""><font color=3D"#888888">
<p></p><br></font></span></blockquote><div>=A0</div></div>I would like to a=
ccess the original proposal to view it in detail.<br></div><div class=3D"gm=
ail_extra"><br></div><div class=3D"gmail_extra" style>Regards,</div><div cl=
ass=3D"gmail_extra" style>
<br></div></div>
<p></p>
-- <br />
<br />
<br />
<br />
--20cf303349618b80c504d2c011c5--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 8 Jan 2013 01:03:16 -0800 (PST)
Raw View
------=_Part_114_18390105.1357635796146
Content-Type: text/plain; charset=ISO-8859-1
On Monday, January 7, 2013 9:17:56 PM UTC-8, Fernando Pelliccioni wrote:
>
> On Mon, Jan 7, 2013 at 6:35 PM, Nicol Bolas <jmck...@gmail.com<javascript:>
> > wrote:
>
>>
>>
>> On Monday, January 7, 2013 5:15:29 AM UTC-8, Fernando Pelliccioni wrote:
>>
>>>
>>> Hi Nicolas,
>>>
>>> I think your proposal combined with "Named Arguments" (I can not find
>>> the paper) could be useful.
>>>
>>> I don't know the details of the "Named Arguments" proposal, but, from
>>> Bjarne's "The Design and Evolution of C++" Section 6.5.1:
>>> "Roland Hartinger's proposal for keyword arguments, that is, for a
>>> mechanism for specifying arguments by name in a call, was close to
>>> technically perfect. The reason the proposal was withdrawn rather than
>>> accepted is therefore particularly interesting. ..."
>>>
>>>
>>> Without having analyzed in depth, I imagine something like this:
>>>
>>> vector<int> v1{20}; //Creates an array of 1 item.
>>> vector<int> v2{ count := 20 }; //Creates an array of 20 items.
>>> vector<int> v3{20, 30, 40}; //Creates an array of 3 items.
>>>
>>>
>>> I think this syntax is clearer, less ugly and also gives us an excuse to
>>> incorporate "Named Arguments" into the language.
>>>
>>
>> Except that it doesn't really solve the actual problem in question.
>> Observe:
>>
>> vector<int> v1{20}; //Creates an array of 1 item.
>>
>> vector<Type> v1{20}; //Creates an array 20 Types.
>>
>>
> Perfect, like C++11
>
How is that "perfect" by any definition? Why should the same initializer do
two *completely different things* to the resulting object? Just because you
changed the template's type. That's not exactly "uniform" initialization,
is it? Constructor syntax is not ambiguous about what gets called: you call
a constructor. So why should uniform initialization syntax be so oddball
that it can radically change what it does based on the type being
initialized.
As I point out in the proposal, this means that you cannot do `T v1{20};`
in a template context. Or even just `std::vector<T> v1{20};` Because you
don't know which constructor it will call; it may do the wrong thing from
your intentions.
If you can't trust {} syntax, then what purpose does it serve? My proposal
is intended to make it more trustworthy by allowing the user to more
explicitly specify what they actually want.
If you used {l:} instead:
>>
>> vector<int> v1{l: 20}; //Creates an array of 1 item.
>> vector<Type> v1{l: 20}; //Compiler error; no matching
>> initializer_list constructor
>>
>>
> What is supposed to be "l:" ?
> Is the name of a constructor parameter ?
>
It's in the proposal. You should familiarize yourself with it, particularly
version 2, before commenting further.
Then you get a proper compiler error. The person doing the initialization
>> has the ability to explicitly state what they want to call and what they
>> don't.
>>
>>
> I don't understand what the point of this example.
>
The example shows that your grammar doesn't solve the problem. The problem,
as stated, is that uniform initialization picks initializer_list
constructors first. Because of that, it can hide others.
Your solution has the these problems, as outlined in my example:
1: The user has no way to force the use of initializer_list constructors.
It doesn't allow the user to say "I want to use an initializer_list
constructor, and if one doesn't match for this type, stop compiling: the
user did something wrong." You could do that with constructors:
`std::vector<T> v1({10});` will not compile if T is not an `int` or some
integer type that is appropriately sized. Uniform initialization should be
able to do everything that constructor syntax can (modulo uniformity and
ditching narrowing).
2: It forces the use of named argument calling if you want to explicitly
call a constructor. Functions in C++ do not have to name their arguments.
Furthermore, putting argument names in template concepts is a dubious
prospect, as there are certainly no mechanisms to use std::enable_if or any
similar construct on them.
3: It breaks aggregate initialization. Therefore, you cannot *uniformly*use the same syntax to initialize a type without knowing what the type is.
Thus, it violates the whole point of uniform initialization.
> Also, how does that work with aggregate initialization? Does it cause the
>> initialization of a particular named field of the aggregate?
>>
>>
> I think it does not apply in this case.
>
We're not just talking about the one case of initializing a std::vector.
We're talking about all initialization of anything.
> How does your proposal work with aggregate initialization?
>
Very well. Exactly as it does for uniform initialization, as stated in the
proposal. The only thing it changes is the list of constructors that are
chosen from, if constructors are being looked at. Aggregates don't have
constructors, so they use aggregate initialization rules.
> Plus, there's the general issue with named parameters at all, which is a
>> very foreign concept to C++ in general.
>>
>
> "foreign concept to C++" not disqualify its usefulness.
> It is a common concept, like many other additions to C++ that have come
> from other languages.
>
And many other languages don't have that concept. Moreover, it's rather
off-topic, as it doesn't solve this particular problem, as stated.
Suggesting a giant feature to solve a small problem is not a good plan for
success.
--
------=_Part_114_18390105.1357635796146
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Monday, January 7, 2013 9:17:56 PM UTC-8, Fernando Pelliccioni w=
rote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><di=
v class=3D"gmail_quote">On Mon, Jan 7, 2013 at 6:35 PM, Nicol Bolas <span d=
ir=3D"ltr"><<a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mai=
lto=3D"7_uO2EKjW5QJ">jmck...@gmail.com</a>></span> wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-=
left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p=
adding-left:1ex"><br><br>On Monday, January 7, 2013 5:15:29 AM UTC-8, Ferna=
ndo Pelliccioni wrote:<div>
<div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bo=
rder-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:so=
lid;padding-left:1ex"><div dir=3D"ltr"><div><div class=3D"gmail_quote"><br>=
<div><div>Hi Nicolas,</div><div><br></div><div>I think your proposal combin=
ed with "Named Arguments" (I can not find the paper) could be useful.</div>=
<div><br></div>
<div>I don't know the details of the "Named Arguments" proposal, but, from =
Bjarne's "The Design and Evolution of C++" Section 6.5.1:</div><div>"Roland=
Hartinger's proposal for keyword arguments, that is, for a</div>
<div>mechanism for specifying arguments by name in a call, was close to</di=
v><div>technically perfect. The reason the proposal was withdrawn rather th=
an</div><div>accepted is therefore particularly interesting. ..."</div>
<div><br></div><div><br></div><div>Without having analyzed in depth, I imag=
ine something like this:</div><div><br></div><div>vector<int> v1{20};=
//Creates an array of 1 item.</d=
iv><div>vector<int> v2{ count :=3D 20 }; //Creates an array of =
20 items.</div>
<div>vector<int> v3{20, 30, 40}; //Creates an array of =
3 items.</div><div><br></div><div><br></div><div>I think this syntax is cle=
arer, less ugly and also gives us an excuse to incorporate "Named Arguments=
" into the language.</div>
</div></div></div></div></blockquote></div></div><div><br>Except that it do=
esn't really solve the actual problem in question. Observe:<br><br><div sty=
le=3D"background-color:rgb(250,250,250);border:1px solid rgb(187,187,187);w=
ord-wrap:break-word">
<code><div><div><span>vector</span><span style=3D"color:rgb(0,136,0)"><i=
nt></span><span> v1</span><span style=3D"color:rgb(102,102,0)">{</span><=
span style=3D"color:rgb(0,102,102)">20</span><span style=3D"color:rgb(102,1=
02,0)">};</span><span> </span><sp=
an style=3D"color:rgb(136,0,0)">//Creates an array of 1 item.</span></div>
<span><br>vector</span><span style=3D"color:rgb(102,102,0)"><</span><spa=
n style=3D"color:rgb(102,0,102)">Type</span><span style=3D"color:rgb(102,10=
2,0)">></span><span> v1</span><span style=3D"color:rgb(102,102,0)">{</sp=
an><span style=3D"color:rgb(0,102,102)">20</span><span style=3D"color:rgb(1=
02,102,0)">};</span><span> </span>=
<span style=3D"color:rgb(136,0,0)">//Creates an array 20 Types.</span><span=
><br>
</span></div></code></div><br></div></blockquote><div><br></div><div>Perfec=
t, like C++11</div></div></div></div></blockquote><div><br>How is that "per=
fect" by any definition? Why should the same initializer do two <i>complete=
ly different things</i> to the resulting object? Just because you changed t=
he template's type. That's not exactly "uniform" initialization, is it? Con=
structor syntax is not ambiguous about what gets called: you call a constru=
ctor. So why should uniform initialization syntax be so oddball that it can=
radically change what it does based on the type being initialized.<br><br>=
As I point out in the proposal, this means that you cannot do `T v1{20};` i=
n a template context. Or even just `std::vector<T> v1{20};` Because y=
ou don't know which constructor it will call; it may do the wrong thing fro=
m your intentions.<br><br>If you can't trust {} syntax, then what purpose d=
oes it serve? My proposal is intended to make it more trustworthy by allowi=
ng the user to more explicitly specify what they actually want.<br><br></di=
v><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><div c=
lass=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"margin:0px =
0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);bord=
er-left-style:solid;padding-left:1ex">
<div>If you used {l:} instead:<br><br><div style=3D"background-color:rgb(25=
0,250,250);border:1px solid rgb(187,187,187);word-wrap:break-word"><code><d=
iv><span>vector</span><span style=3D"color:rgb(0,136,0)"><int></span>=
<span> v1</span><span style=3D"color:rgb(102,102,0)">{</span><span>l</span>=
<span style=3D"color:rgb(102,102,0)">:</span><span> </span><span style=3D"c=
olor:rgb(0,102,102)">20</span><span style=3D"color:rgb(102,102,0)">};</span=
><span> </span><span style=3D"color:rgb(136,0,0=
)">//Creates an array of 1 item.</span><span><br>
vector</span><span style=3D"color:rgb(102,102,0)"><</span><span style=3D=
"color:rgb(102,0,102)">Type</span><span style=3D"color:rgb(102,102,0)">>=
</span><span> v1</span><span style=3D"color:rgb(102,102,0)">{</span><span>l=
</span><span style=3D"color:rgb(102,102,0)">:</span><span> </span><span sty=
le=3D"color:rgb(0,102,102)">20</span><span style=3D"color:rgb(102,102,0)">}=
;</span><span> </span><span style=3D"color:rgb(1=
36,0,0)">//Compiler error; no matching initializer_list constructor</span><=
span><br>
</span></div></code></div><br></div></blockquote><div><br></div><div>What i=
s supposed to be "l:" ?<br></div><div>Is the name of a constructor paramete=
r ?<br></div></div></div></div></blockquote><div><br>It's in the proposal. =
You should familiarize yourself with it, particularly version 2, before com=
menting further.<br><br></div><blockquote class=3D"gmail_quote" style=3D"ma=
rgin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">=
<div dir=3D"ltr"><div><div class=3D"gmail_quote"><blockquote class=3D"gmail=
_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left=
-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div>Then you get a proper compiler error. The person doing the initializat=
ion has the ability to explicitly state what they want to call and what the=
y don't.<br><br></div></blockquote><div><br></div><div>I don't understand w=
hat the point of this example.<br></div></div></div></div></blockquote><div=
><br>The example shows that your grammar doesn't solve the problem. The pro=
blem, as stated, is that uniform initialization picks initializer_list cons=
tructors first. Because of that, it can hide others.<br><br>Your solution h=
as the these problems, as outlined in my example:<br><br>1: The user has no=
way to force the use of initializer_list constructors. It doesn't allow th=
e user to say "I want to use an initializer_list constructor, and if one do=
esn't match for this type, stop compiling: the user did something wrong." Y=
ou could do that with constructors: `std::vector<T> v1({10});` will n=
ot compile if T is not an `int` or some integer type that is appropriately =
sized. Uniform initialization should be able to do everything that construc=
tor syntax can (modulo uniformity and ditching narrowing).<br><br>2: It for=
ces the use of named argument calling if you want to explicitly call a cons=
tructor. Functions in C++ do not have to name their arguments. Furthermore,=
putting argument names in template concepts is a dubious prospect, as ther=
e are certainly no mechanisms to use std::enable_if or any similar construc=
t on them.<br><br>3: It breaks aggregate initialization. Therefore, you can=
not <i>uniformly</i> use the same syntax to initialize a type without knowi=
ng what the type is. Thus, it violates the whole point of uniform initializ=
ation.<br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;=
margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=
=3D"ltr"><div><div class=3D"gmail_quote"><div>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;b=
order-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:s=
olid;padding-left:1ex"><div>Also, how does that work with aggregate initial=
ization? Does it cause the initialization of a particular named field of th=
e aggregate?<br>
<br></div></blockquote><div><br></div><div>I think it does not apply in thi=
s case.<br></div></div></div></div></blockquote><div><br>We're not just tal=
king about the one case of initializing a std::vector. We're talking about =
all initialization of anything.<br> </div><blockquote class=3D"gmail_q=
uote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pad=
ding-left: 1ex;"><div dir=3D"ltr"><div><div class=3D"gmail_quote"><div></di=
v><div>How does your proposal work with aggregate initialization?<br></div>=
</div></div></div></blockquote><div><br>Very well. Exactly as it does for u=
niform initialization, as stated in the proposal. The only thing it changes=
is the list of constructors that are chosen from, if constructors are bein=
g looked at. Aggregates don't have constructors, so they use aggregate init=
ialization rules.<br> </div><blockquote class=3D"gmail_quote" style=3D=
"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex=
;"><div dir=3D"ltr"><div><div class=3D"gmail_quote"><blockquote class=3D"gm=
ail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-l=
eft-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div>Plus, there's the general issue with named parameters at all, which is=
a very foreign concept to C++ in general.</div></blockquote><div><br></div=
><div>"foreign concept to C++" not disqualify its usefulness.</div>
<div>It is a common concept, like many other additions to C++ that hav=
e come from other languages. </div></div></div></div></blockquote><div=
><br>And many other languages don't have that concept. Moreover, it's rathe=
r off-topic, as it doesn't solve this particular problem, as stated.<br><br=
>Suggesting a giant feature to solve a small problem is not a good plan for=
success.<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_114_18390105.1357635796146--
.
Author: Sebastian Gesemann <s.gesemann@gmail.com>
Date: Tue, 8 Jan 2013 10:12:40 +0100
Raw View
On Sun, Dec 30, 2012 at 10:49 PM, Nicol Bolas wrote:
>
> Introduction
> [...]
> In a perfect world, we would always use uniform initialization and
> never use direct constructor syntax.
I'm fine with the way it's currently handled. I'm fine with being able to w=
rite
vector<int> foo (20,30); // 20 elements with value 30
vector<int> foo {20,30}; // 2 elements with value 20 and 30
to distinguish between the more specialized direct initialization and
a "logical, aggregate-like" initialization.
> However, despite being called =93uniform initialization,=94 it cannot be
> uniformly used everywhere, due to a critical flaw that prevents its use
> towards these ends.
I don't think this syntax was ever intended to be the only kind of
initialization everybody should use from now on in every situation.
> This proposal intends to correct this flaw, thus
> allowing it to be used in all possible cases of object construction, whil=
e
> having well-defined results.
Why?
> Motivation and Scope
Ok, convince me.
> The flaw in uniform initialization is quite simple to see in the standard
> library. The std::vector type has an explicit constructor which takes a
> single std::vector::size_type, which is an integral type. std::vector als=
o
> has a constructor that takes an initializer_list<T>.
>
> For most types, these constructors can coexist with uniform initializatio=
n
> quite reasonably. For example:
>
> std::vector<A> v1{20};
> std::vector<A> v2{A{}};
> std::vector<A> v3{A{}, A{}, A{}};
>
> In this example, v1 is an array of 20 value-constructed values. v2 is an
> array of 1 value-constructed element. v3 is an array of 3 value-construct=
ed
> elements.
>
> This is all well and good, until we do this:
>
> std::vector<int> v1{20};
> std::vector<int> v2{int{}};
> std::vector<int> v3{int{}, int{}, int{}};
>
> v2 and v3 retain their old meaning. But v1 is now very different. It is a=
n
> array containing a single element, the number 20. Why?
Why not? I find it makes sense. Logically, a vector<int> is an
aggregate of a variable number of ints and the curly braces are just a
way of initializing this "aggregate-style" types. I tend to think of
{} as the kind of initialization which specifies the (logical)
elements of the to-be-initialized object.
> Because uniform initialization syntax always prefers initializer list
> constructors if one is available that would fit the braced-init-list. Thi=
s
> is a consequence of uniform initialization syntax using the same syntax a=
s
> initializer lists: the braced-init-list. And since
> std::vector<int>::vector(std::initializer_list<int>) matches the
> braced-init-list ({20}), it will be preferred over
> std::vector<int>::vector(std::vector<int>::size_type)
>
> This is a problem because there is no way to get at the size_type
> constructor via uniform initialization. There is no syntax that we can
> employ which will cause the conflicting initializer_list constructor to b=
e
> ignored or to do anything else that would allow us to get at a different =
set
> of constructors.
Sure, there is a syntax:
vector<int> v1(20);
That's what direct initialization is for.
> But consider code that is generic on the vector's type:
>
> template<typename T>
> std::vector<T> MakeVector()
> {
> return std::vector<T>{20};
> }
>
> By all rights, this code should always do the same thing: return a
> vector containing 20 value-initialized elements. But it does not.
> MakeVector<int>()
> will return a vector containing exactly one element.
So? If you want the vector to contain 20 default constructed elements
use the proper initialization syntax!
> This is of much greater concern when dealing with more intricate
> templates. Consider the following trivial template function:
>
> template<typename T>
> T Process()
> {
> T t{};
> //do stuff with t;
> return T{t};
> }
>
> This function creates a temporary, does some processing, and returns
> a copy of it. This function requires that T be DefaultConstructible
> and CopyConstructible, in addition to whatever =93do stuff with t=94
> requires.
I find your examples hardly convincing. What problkem is Process<>
supposed to solve? Why don't you just return t?
I think the issue is that you think you are supposed to use {}
everywhere but you're not.
> Design Overview
>
> The idea is quite simple. We will divide braced-init-list up into two
> variation: list-braced-init-list and constr-braced-init-list. Most of
> the text will remain the exact same, as they have almost identical
> behavior.
As far as I am concerned it is not clear what problem you are trying to
solve. Sorry, I don't consider "I can't use curly braces for
everything" to be a problem.
> The big issue is how constr-braced-init-lists are defined in the
> grammar. It should look like this:
>
> {^ ... }
>
> The =93{=94 token followed by the =93^=94 token is what distinguishes the
> constr-braced-init-list from a list-braced-init-list.
I don't like it. It does not seem to solve any problems but only cause
more. For example, this is not "perfectly forwardable".
If you intent to write your own types and like to be able to
distinguish between different constructors, consider tag dispatching
(like std::piecewise for std::pair).
my 2 cents,
Sebastian
--=20
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 8 Jan 2013 01:35:37 -0800 (PST)
Raw View
------=_Part_903_27330903.1357637738044
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Tuesday, January 8, 2013 1:12:40 AM UTC-8, Sebastian Gesemann wrote:
>
> On Sun, Dec 30, 2012 at 10:49 PM, Nicol Bolas wrote:=20
> >=20
> > Introduction=20
> > [...]=20
> > In a perfect world, we would always use uniform initialization and=20
> > never use direct constructor syntax.=20
>
> I'm fine with the way it's currently handled. I'm fine with being able to=
=20
> write=20
>
> vector<int> foo (20,30); // 20 elements with value 30=20
> vector<int> foo {20,30}; // 2 elements with value 20 and 30=20
>
> to distinguish between the more specialized direct initialization and=20
> a "logical, aggregate-like" initialization.=20
>
> > However, despite being called =93uniform initialization,=94 it cannot b=
e=20
> > uniformly used everywhere, due to a critical flaw that prevents its use=
=20
> > towards these ends.=20
>
> I don't think this syntax was ever intended to be the only kind of=20
> initialization everybody should use from now on in every situation.=20
>
> > This proposal intends to correct this flaw, thus=20
> > allowing it to be used in all possible cases of object construction,=20
> while=20
> > having well-defined results.=20
>
> Why?=20
>
> > Motivation and Scope=20
>
> Ok, convince me.=20
>
> > The flaw in uniform initialization is quite simple to see in the=20
> standard=20
> > library. The std::vector type has an explicit constructor which takes a=
=20
> > single std::vector::size_type, which is an integral type. std::vector=
=20
> also=20
> > has a constructor that takes an initializer_list<T>.=20
> >=20
> > For most types, these constructors can coexist with uniform=20
> initialization=20
> > quite reasonably. For example:=20
> >=20
> > std::vector<A> v1{20};=20
> > std::vector<A> v2{A{}};=20
> > std::vector<A> v3{A{}, A{}, A{}};=20
> >=20
> > In this example, v1 is an array of 20 value-constructed values. v2 is a=
n=20
> > array of 1 value-constructed element. v3 is an array of 3=20
> value-constructed=20
> > elements.=20
> >=20
> > This is all well and good, until we do this:=20
> >=20
> > std::vector<int> v1{20};=20
> > std::vector<int> v2{int{}};=20
> > std::vector<int> v3{int{}, int{}, int{}};=20
> >=20
> > v2 and v3 retain their old meaning. But v1 is now very different. It is=
=20
> an=20
> > array containing a single element, the number 20. Why?=20
>
> Why not? I find it makes sense. Logically, a vector<int> is an=20
> aggregate of a variable number of ints and the curly braces are just a=20
> way of initializing this "aggregate-style" types. I tend to think of=20
> {} as the kind of initialization which specifies the (logical)=20
> elements of the to-be-initialized object.=20
>
But that's not how the feature is designed. If it's only supposed to be=20
used in cases of aggregate and initializer_list initialization, why does=20
this work:
std::vector<Type> v1{20}; //Creates a vector of 20 default-constructed=20
items.
If the above compiles, then clearly the *design* of the feature is to be=20
usable for *more* than just aggregate and list initialization. It's there=
=20
to solve the Most Vexing Parse issue and be usable in all cases of=20
initialization.
Therefore, if the feature can't be used everywhere, then it's not living up=
=20
to its intended purpose: to universally replace all initialization. The=20
purpose of this feature is to make uniform initialization usable in all=20
contexts, so that C++ programmers don't have to go "well, sometimes we use=
=20
{} to initialize, but you can't trust it so most of the time you use (),=20
except when your compiler thinks it's a function so you use {} again, but=
=20
not when..."
It makes the language simpler to use.
> Design Overview=20
> >=20
> > The idea is quite simple. We will divide braced-init-list up into two=
=20
> > variation: list-braced-init-list and constr-braced-init-list. Most of=
=20
> > the text will remain the exact same, as they have almost identical=20
> > behavior.=20
>
> As far as I am concerned it is not clear what problem you are trying to=
=20
> solve. Sorry, I don't consider "I can't use curly braces for=20
> everything" to be a problem.=20
>
These two statements seem contradictory. You clearly see what I'm talking=
=20
about; you just don't accept that it is a *problem*. There's a difference=
=20
between saying "You're not being clear" and "I understand what you're=20
saying but I don't buy it".
I don't like it. It does not seem to solve any problems but only cause=20
> more. For example, this is not "perfectly forwardable".=20
>
{} is not "perfectly forwardable" as it currently stands either. A=20
braced-init-list cannot be used in a parameter pack or any other template=
=20
deduction contexts.
It's a problem before this proposal and it remains one after. It's not a=20
problem this proposal is intended to solve.
=20
> If you intent to write your own types and like to be able to=20
> distinguish between different constructors, consider tag dispatching=20
> (like std::piecewise for std::pair).=20
>
As stated in the proposal, the problem is that it only solves it for that=
=20
type. This is a problem introduced by a language feature. If you try to=20
solve it at the code level, then everyone will have to implement their own,=
=20
slightly different and completely incompatible solution. It still won't be=
=20
something you can depend on in template code when the types are unknown.
In short, it doesn't solve the problem. Problems caused by language=20
features need language solutions. Trying to fix language problems with=20
library solutions is why we have the nightmarish `std::enable_if` instead=
=20
of the much more sane, rational, and powerful `static if`.
--=20
------=_Part_903_27330903.1357637738044
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
<br><br>On Tuesday, January 8, 2013 1:12:40 AM UTC-8, Sebastian Gesemann wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">On Sun, Dec 30, 2012 at 10=
:49 PM, Nicol Bolas wrote:
<br>>
<br>> Introduction
<br>> [...]
<br>> In a perfect world, we would always use uniform initialization and
<br>> never use direct constructor syntax.
<br>
<br>I'm fine with the way it's currently handled. I'm fine with being able =
to write
<br>
<br> vector<int> foo (20,30); // 20 elements with value 30
<br> vector<int> foo {20,30}; // 2 elements with value 20 and 3=
0
<br>
<br>to distinguish between the more specialized direct initialization and
<br>a "logical, aggregate-like" initialization.
<br>
<br>> However, despite being called =93uniform initialization,=94 it can=
not be
<br>> uniformly used everywhere, due to a critical flaw that prevents it=
s use
<br>> towards these ends.
<br>
<br>I don't think this syntax was ever intended to be the only kind of
<br>initialization everybody should use from now on in every situation.
<br>
<br>> This proposal intends to correct this flaw, thus
<br>> allowing it to be used in all possible cases of object constructio=
n, while
<br>> having well-defined results.
<br>
<br>Why?
<br>
<br>> Motivation and Scope
<br>
<br>Ok, convince me.
<br>
<br>> The flaw in uniform initialization is quite simple to see in the s=
tandard
<br>> library. The std::vector type has an explicit constructor which ta=
kes a
<br>> single std::vector::size_type, which is an integral type. std::vec=
tor also
<br>> has a constructor that takes an initializer_list<T>.
<br>>
<br>> For most types, these constructors can coexist with uniform initia=
lization
<br>> quite reasonably. For example:
<br>>
<br>> std::vector<A> v1{20};
<br>> std::vector<A> v2{A{}};
<br>> std::vector<A> v3{A{}, A{}, A{}};
<br>>
<br>> In this example, v1 is an array of 20 value-constructed values. v2=
is an
<br>> array of 1 value-constructed element. v3 is an array of 3 value-co=
nstructed
<br>> elements.
<br>>
<br>> This is all well and good, until we do this:
<br>>
<br>> std::vector<int> v1{20};
<br>> std::vector<int> v2{int{}};
<br>> std::vector<int> v3{int{}, int{}, int{}};
<br>>
<br>> v2 and v3 retain their old meaning. But v1 is now very different. =
It is an
<br>> array containing a single element, the number 20. Why?
<br>
<br>Why not? I find it makes sense. Logically, a vector<int> is an
<br>aggregate of a variable number of ints and the curly braces are just a
<br>way of initializing this "aggregate-style" types. I tend to think of
<br>{} as the kind of initialization which specifies the (logical)
<br>elements of the to-be-initialized object.
<br></blockquote><div><br>But that's not how the feature is designed. If it=
's only supposed to be=20
used in cases of aggregate and initializer_list initialization, why does
this work:<br><br><div class=3D"prettyprint" style=3D"background-color: rg=
b(250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; bo=
rder-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div c=
lass=3D"subprettyprint"><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify">std</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">vector</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify"><</span><=
span style=3D"color: #606;" class=3D"styled-by-prettify">Type</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">></span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> v1</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #066;=
" class=3D"styled-by-prettify">20</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">};</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-pre=
ttify">//Creates a vector of 20 default-constructed items.</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"><br></span></div></code></d=
iv><br>If the above compiles, then clearly the <i>design</i> of the feature=
is to be usable for <i>more</i>
than just aggregate and list initialization. It's there to solve the=20
Most Vexing Parse issue and be usable in all cases of initialization.<br><b=
r>Therefore, if the feature can't be used everywhere, then it's not living =
up to its intended purpose: to universally replace all initialization. The
purpose of this feature is to make uniform initialization usable in all
contexts, so that C++ programmers don't have to go "well, sometimes we=20
use {} to initialize, but you can't trust it so most of the time you use
(), except when your compiler thinks it's a function so you use {}=20
again, but not when..."<br><br>It makes the language simpler to use.<br><br=
></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.=
8ex;border-left: 1px #ccc solid;padding-left: 1ex;">> Design Overview
<br>>
<br>> The idea is quite simple. We will divide braced-init-list up into =
two
<br>> variation: list-braced-init-list and constr-braced-init-list. Most=
of
<br>> the text will remain the exact same, as they have almost identical
<br>> behavior.
<br>
<br>As far as I am concerned it is not clear what problem you are trying to
<br>solve. Sorry, I don't consider "I can't use curly braces for
<br>everything" to be a problem.
<br></blockquote><div><br>These two statements seem contradictory. You clea=
rly see what I'm talking about; you just don't accept that it is a <i>probl=
em</i>. There's a difference between saying "You're not being clear" and "I=
understand what you're saying but I don't buy it".<br><br></div><blockquot=
e class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: =
1px #ccc solid;padding-left: 1ex;">
I don't like it. It does not seem to solve any problems but only cause
<br>more. For example, this is not "perfectly forwardable".
<br></blockquote><div><br>{} is not "perfectly forwardable" as it currently=
stands either. A braced-init-list cannot be used in a parameter pack or an=
y other template deduction contexts.<br><br>It's a problem before this prop=
osal and it remains one after. It's not a problem this proposal is intended=
to solve.<br> </div><blockquote class=3D"gmail_quote" style=3D"margin=
: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
If you intent to write your own types and like to be able to
<br>distinguish between different constructors, consider tag dispatching
<br>(like std::piecewise for std::pair).
<br></blockquote><div><br>As stated in the proposal, the problem is that it=
only solves it for that type. This is a problem introduced by a language f=
eature. If you try to solve it at the code level, then everyone will have t=
o implement their own, slightly different and completely incompatible solut=
ion. It still won't be something you can depend on in template code when th=
e types are unknown.<br><br>In short, it doesn't solve the problem. Problem=
s caused by language features need language solutions. Trying to fix langua=
ge problems with library solutions is why we have the nightmarish `std::ena=
ble_if` instead of the much more sane, rational, and powerful `static if`.<=
br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_903_27330903.1357637738044--
.
Author: Nevin Liber <nevin@eviloverlord.com>
Date: Tue, 8 Jan 2013 09:57:16 -0600
Raw View
--f46d04088f7bbb9d7004d2c9172d
Content-Type: text/plain; charset=ISO-8859-1
On 8 January 2013 03:35, Nicol Bolas <jmckesson@gmail.com> wrote:
>
> If the above compiles, then clearly the *design* of the feature is to be
> usable for *more* than just aggregate and list initialization. It's there
> to solve the Most Vexing Parse issue
>
How does {} not solve the most vexing parse issue? And at the call site, I
don't see how anyone can mix up passing no parameters to a constructor vs.
passing at least one parameter to a constructor.
> and be usable in all cases of initialization.
>
> Therefore, if the feature can't be used everywhere, then it's not living
> up to its intended purpose: to universally replace all initialization. The
> purpose of this feature is to make uniform initialization usable in all
> contexts, so that C++ programmers don't have to go "well, sometimes we use
> {} to initialize, but you can't trust it so most of the time you use (),
> except when your compiler thinks it's a function so you use {} again, but
> not when..."
>
And you want to add *three more* ways and *four more* cryptic syntaxes to
do initialization:
>
> - "l": Only look at initializer_list constructors.
> - "c": Only look at non-initializer_list constructors.
> - "lc": Look at initializer_list constructors first. Equivalent to {}.
> - "cl": Look at non-initializer_list constructors first.
>
>
> It makes the language simpler to use.
>
Given that most people read code far more often than they write it, I just
don't see how having to learn the subtleties of *seven* (the seventh being
value initialization vs. default initialization) different syntaxes is
simplier than learning just three.
"Uniform" is supposed to mean *one*, not *seven*. I agree that the
standard doesn't quite achieve it, but this proposal doesn't either.
{} is not "perfectly forwardable" as it currently stands either. A
> braced-init-list cannot be used in a parameter pack or any other template
> deduction contexts.
>
> It's a problem before this proposal and it remains one after. It's not a
> problem this proposal is intended to solve.
>
So we'll need even *more* syntaxes to solve other related issues? What
happened to simpler?
--
Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404
--
--f46d04088f7bbb9d7004d2c9172d
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On 8 January 2013 03:35, Nicol Bolas <span dir=3D"ltr"><<a href=3D"mailt=
o:jmckesson@gmail.com" target=3D"_blank">jmckesson@gmail.com</a>></span>=
wrote:<br><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" sty=
le=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class=3D"HOEnZb"><div><br>If the above compiles, then clearly the <i>d=
esign</i> of the feature is to be usable for <i>more</i>
than just aggregate and list initialization. It's there to solve the=
=20
Most Vexing Parse issue</div></div></blockquote><div><br>How does {} not so=
lve the most vexing parse issue?=A0 And at the call site, I don't see h=
ow anyone can mix up passing no parameters to a constructor vs. passing at =
least one parameter to a constructor.<br>
=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;borde=
r-left:1px #ccc solid;padding-left:1ex"><div class=3D"HOEnZb"><div> and be =
usable in all cases of initialization.<br><br>Therefore, if the feature can=
't be used everywhere, then it's not living up to its intended purp=
ose: to universally replace all initialization. The
purpose of this feature is to make uniform initialization usable in all
contexts, so that C++ programmers don't have to go "well, sometim=
es we=20
use {} to initialize, but you can't trust it so most of the time you us=
e
(), except when your compiler thinks it's a function so you use {}=20
again, but not when..."<br></div></div></blockquote><div><br>And you w=
ant to add *three more* ways and *four more* cryptic syntaxes to do initial=
ization:<br><blockquote style=3D"margin:0px 0px 0px 0.8ex;border-left:1px s=
olid rgb(204,204,204);padding-left:1ex" class=3D"gmail_quote">
<ul><li>"l": Only look at initializer_list constructors.</li><li>=
"c": Only look at non-initializer_list constructors.</li><li>&quo=
t;lc": Look at initializer_list constructors first. Equivalent to {}.<=
br>
</li><li>"cl": Look at non-initializer_list constructors first.</=
li></ul></blockquote></div><blockquote class=3D"gmail_quote" style=3D"margi=
n:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class=3D"HOE=
nZb">
<div><br>It makes the language simpler to use.<br></div></div></blockquote>=
<div><br>Given that most people read code far more often than they write it=
, I just don't see how having to learn the subtleties of *seven* (the s=
eventh being value initialization vs. default initialization) different syn=
taxes is simplier than learning just three.<br>
<br>"Uniform" is supposed to mean *one*, not *seven*.=A0 I agree =
that the standard doesn't quite achieve it, but this proposal doesn'=
;t either.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0=
0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>{} is not "perfectly forwardable" as it currently stands eit=
her. A braced-init-list cannot be used in a parameter pack or any other tem=
plate deduction contexts.<br><br>It's a problem before this proposal an=
d it remains one after. It's not a problem this proposal is intended to=
solve.<br>
</div></blockquote><div><br>So we'll need even *more* syntaxes to solve=
other related issues?=A0 What happened to simpler?<br></div></div>-- <br>=
=A0Nevin ":-)" Liber=A0 <mailto:<a href=3D"mailto:nevin@evilov=
erlord.com" target=3D"_blank">nevin@eviloverlord.com</a>>=A0 (847) 691-1=
404
<p></p>
-- <br />
<br />
<br />
<br />
--f46d04088f7bbb9d7004d2c9172d--
.
Author: Jeffrey Yasskin <jyasskin@googlers.com>
Date: Tue, 8 Jan 2013 08:46:28 -0800
Raw View
On Tue, Jan 8, 2013 at 1:35 AM, Nicol Bolas <jmckesson@gmail.com> wrote:
>
>
> On Tuesday, January 8, 2013 1:12:40 AM UTC-8, Sebastian Gesemann wrote:
>>
>> On Sun, Dec 30, 2012 at 10:49 PM, Nicol Bolas wrote:
>> >
>> > Introduction
>> > [...]
>> > In a perfect world, we would always use uniform initialization and
>> > never use direct constructor syntax.
>>
>> I'm fine with the way it's currently handled. I'm fine with being able t=
o
>> write
>>
>> vector<int> foo (20,30); // 20 elements with value 30
>> vector<int> foo {20,30}; // 2 elements with value 20 and 30
>>
>> to distinguish between the more specialized direct initialization and
>> a "logical, aggregate-like" initialization.
>>
>> > However, despite being called =93uniform initialization,=94 it cannot =
be
>> > uniformly used everywhere, due to a critical flaw that prevents its us=
e
>> > towards these ends.
>>
>> I don't think this syntax was ever intended to be the only kind of
>> initialization everybody should use from now on in every situation.
>>
>> > This proposal intends to correct this flaw, thus
>> > allowing it to be used in all possible cases of object construction,
>> > while
>> > having well-defined results.
>>
>> Why?
>>
>> > Motivation and Scope
>>
>> Ok, convince me.
>>
>> > The flaw in uniform initialization is quite simple to see in the
>> > standard
>> > library. The std::vector type has an explicit constructor which takes =
a
>> > single std::vector::size_type, which is an integral type. std::vector
>> > also
>> > has a constructor that takes an initializer_list<T>.
>> >
>> > For most types, these constructors can coexist with uniform
>> > initialization
>> > quite reasonably. For example:
>> >
>> > std::vector<A> v1{20};
>> > std::vector<A> v2{A{}};
>> > std::vector<A> v3{A{}, A{}, A{}};
>> >
>> > In this example, v1 is an array of 20 value-constructed values. v2 is =
an
>> > array of 1 value-constructed element. v3 is an array of 3
>> > value-constructed
>> > elements.
>> >
>> > This is all well and good, until we do this:
>> >
>> > std::vector<int> v1{20};
>> > std::vector<int> v2{int{}};
>> > std::vector<int> v3{int{}, int{}, int{}};
>> >
>> > v2 and v3 retain their old meaning. But v1 is now very different. It i=
s
>> > an
>> > array containing a single element, the number 20. Why?
>>
>> Why not? I find it makes sense. Logically, a vector<int> is an
>> aggregate of a variable number of ints and the curly braces are just a
>> way of initializing this "aggregate-style" types. I tend to think of
>> {} as the kind of initialization which specifies the (logical)
>> elements of the to-be-initialized object.
>
>
> But that's not how the feature is designed. If it's only supposed to be u=
sed
> in cases of aggregate and initializer_list initialization, why does this
> work:
>
> std::vector<Type> v1{20}; //Creates a vector of 20 default-constructed
> items.
>
> If the above compiles, then clearly the design of the feature is to be
> usable for more than just aggregate and list initialization.
Some types, say, pair<> and tuple<>, have non-initializer-list
constructors taking arguments that represent their contents after
construction. Allowing {} to produce constructor arguments makes
pair<> and tuple<> usable like aggregates. vector<> has a constructor
taking an argument that doesn't represent the contents after
construction but instead describes how to create those contents. There
wasn't a way to prevent vector<>'s constructor from working with list
initialization, so it does, but that doesn't mean allowing it was a
goal. The committee could have added a syntax to mark a constructor as
unusable with list-initialization, but either they didn't think of it
or didn't think it was worth doing. If you want to read the history,
check out the "initializer lists" line in
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2869.html.
-1 on this proposal, agreeing with Nevin. I don't intend to reply further.
Jeffrey
--=20
.
Author: Sebastian Gesemann <s.gesemann@gmail.com>
Date: Tue, 8 Jan 2013 18:23:12 +0100
Raw View
On Tue, Jan 8, 2013 at 10:35 AM, Nicol Bolas wrote:
> On Tuesday, January 8, 2013 1:12:40 AM UTC-8, Sebastian Gesemann wrote:
>>
>> Why not? I find it makes sense. Logically, a vector<int> is an
>> aggregate of a variable number of ints and the curly braces are just a
>> way of initializing this "aggregate-style" types. I tend to think of
>> {} as the kind of initialization which specifies the (logical)
>> elements of the to-be-initialized object.
>
> But that's not how the feature is designed. If it's only supposed to be used
> in cases of aggregate and initializer_list initialization, why does this
> work:
>
> std::vector<Type> v1{20}; //Creates a vector of 20 default-constructed
> items.
I didn't say that {} only works aggregates and for classes with
initializer_list constructor. I am well aware of other classes like
complex<double> where you can initialize objects with curly braces as
well.
What you seem to be annoyed with is the overloading of
std::vector<T>'s constructors and the overload resolution rules.
> If the above compiles, then clearly the design of the feature is to be
> usable for more than just aggregate and list initialization. It's there to
> solve the Most Vexing Parse issue and be usable in all cases of
> initialization.
> Therefore, if the feature can't be used everywhere, then it's not living up
> to its intended purpose: to universally replace all initialization.
But it is _not_ designed to be the syntax for all cases.
>> As far as I am concerned it is not clear what problem you are trying to
>> solve. Sorry, I don't consider "I can't use curly braces for
>> everything" to be a problem.
>
> These two statements seem contradictory. You clearly see what I'm talking
> about; you just don't accept that it is a problem. There's a difference
> between saying "You're not being clear" and "I understand what you're saying
> but I don't buy it".
I don't know how else to express it without repeating myself. But I'll
try: The "problem" is that you think {} is supposed to be applicable
everywhere. This is not a C++ language problem. This is you making a
false assumption.
>> I don't like it. It does not seem to solve any problems but only cause
>> more. For example, this is not "perfectly forwardable".
>
> {} is not "perfectly forwardable" as it currently stands either. A
> braced-init-list cannot be used in a parameter pack or any other template
> deduction contexts.
Correct. But if I remember correctly a member of the standardization
committee already hinted at equalizing the deduction rules between
auto and templates so that in a case like
template<class T> void foo(T)
int main() { foo({1,2,3}); }
the compiler will deduce T to be std::initializer_list<int> just like
it already does for auto:
auto bar = {1,2,3};
in which case you will be able to make this work:
template<class T, class...Args>
unique_ptr<T> make_unique(Args&&...args)
{
unique_ptr<T> p (forward<Args>(args)...);
return p;
}
int main()
{
auto p = make_unique<std::vector<int>>(20); // creates a vector
with 20 elements
auto q = make_unique<std::vector<int>>({20}); // creates a
vector containing the value 20.
}
It won't work in all cases and I think it just cannot but it's good
enoug, I think.
>> If you intent to write your own types and like to be able to
>> distinguish between different constructors, consider tag dispatching
>> (like std::piecewise for std::pair).
>
> As stated in the proposal, the problem is that it only solves it for that
> type. This is a problem introduced by a language feature. If you try to
> solve it at the code level, then everyone will have to implement their own,
> slightly different and completely incompatible solution. It still won't be
> something you can depend on in template code when the types are unknown.
What problem?
Perhaps this is the time where you show us some real code with a real
problem you like solved and not just some "look how {} does not work
like I expected in this case"-examples. ;-)
Cheers!
SG
--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 8 Jan 2013 10:58:46 -0800 (PST)
Raw View
------=_Part_153_15652984.1357671526782
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Tuesday, January 8, 2013 9:23:12 AM UTC-8, Sebastian Gesemann wrote:
>
> On Tue, Jan 8, 2013 at 10:35 AM, Nicol Bolas wrote:=20
> > If the above compiles, then clearly the design of the feature is to be=
=20
> > usable for more than just aggregate and list initialization. It's there=
=20
> to=20
> > solve the Most Vexing Parse issue and be usable in all cases of=20
> > initialization.=20
> > Therefore, if the feature can't be used everywhere, then it's not livin=
g=20
> up=20
> > to its intended purpose: to universally replace all initialization.=20
>
> But it is _not_ designed to be the syntax for all cases.
>
Really? Bjarne Stroustrup developed uniform initialization. So let's ask=20
him what the designed purpose of it is. From N2532, "Uniform Initialization=
=20
design choices (Revision 2)":
*A fundamental aim of =93uniform initialization=94 can be expressed as: =93=
We=20
> want a single syntax that can be used everywhere and wherever it=92s used=
,=20
> the same initialized value results for the same initializer value=94. It =
may=20
> be that the ideal can be only approximated for C++0x, but I argue that it=
=20
> is the ideal.*
>
So yes, the goal very much was something that "can be used everywhere;" it=
=20
is intended to be able to be used in all cases. So it's not "my problem";=
=20
it is very clearly a problem between the intent of uniform initialization=
=20
and the current version as implemented in C++11.
My proposal is simply trying to move from being "approximated" closer to=20
the "ideal".
If you don't like that goal, fine. But you can't argue that this *isn't*the=
goal.
--=20
------=_Part_153_15652984.1357671526782
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
<br><br>On Tuesday, January 8, 2013 9:23:12 AM UTC-8, Sebastian Gesemann wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">On Tue, Jan 8, 2013 at 10:=
35 AM, Nicol Bolas wrote:
<br>> If the above compiles, then clearly the design of the feature is t=
o be
<br>> usable for more than just aggregate and list initialization. It's =
there to
<br>> solve the Most Vexing Parse issue and be usable in all cases of
<br>> initialization.
<br>> Therefore, if the feature can't be used everywhere, then it's not =
living up
<br>> to its intended purpose: to universally replace all initialization=
..
<br>
<br>But it is _not_ designed to be the syntax for all cases.<br></blockquot=
e><div><br>Really? Bjarne Stroustrup developed uniform initialization. So l=
et's ask him what the designed purpose of it is. From N2532, "Uniform Initi=
alization design choices (Revision 2)":<br><br><blockquote style=3D"margin:=
0px 0px 0px 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left=
: 1ex;" class=3D"gmail_quote"><b>A fundamental aim of =93uniform initializa=
tion=94 can be expressed as: =93We want a single syntax that can be used ev=
erywhere and wherever it=92s used, the same initialized value results for t=
he same initializer value=94. It may be that the ideal can be only approxim=
ated for C++0x, but I argue that it is the ideal.</b><br></blockquote><br>S=
o yes, the goal very much was something that "can be used everywhere;" it i=
s intended to be able to be used in all cases. So it's not "my problem"; it=
is very clearly a problem between the intent of uniform initialization and=
the current version as implemented in C++11.<br><br>My proposal is simply =
trying to move from being "approximated" closer to the "ideal".<br><br>If y=
ou don't like that goal, fine. But you can't argue that this <i>isn't</i> t=
he goal.<br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_153_15652984.1357671526782--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 8 Jan 2013 11:14:42 -0800 (PST)
Raw View
------=_Part_264_6609050.1357672482571
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, January 8, 2013 7:57:16 AM UTC-8, Nevin ":-)" Liber wrote:
>
> On 8 January 2013 03:35, Nicol Bolas <jmck...@gmail.com <javascript:>>wrote:
>
>>
>> If the above compiles, then clearly the *design* of the feature is to be
>> usable for *more* than just aggregate and list initialization. It's
>> there to solve the Most Vexing Parse issue
>>
>
> How does {} not solve the most vexing parse issue?
>
Because you *can't use it everywhere*. As pointed out in the proposal, the
shadowing effect of {}'s constructor picking rules means that there's no
way to call certain constructors with {}.
Since you have to default to (), you'll still get the MVP. The most {} does
for you in those cases is that you can use {} to initialize something in
those specific cases. For spot fixes. Then again, you could usually wrap
the type in parenthesis to achieve the same effect.
Without the ability to freely use {} syntax everywhere, it doesn't really
solve the problem.
> And at the call site, I don't see how anyone can mix up passing no
> parameters to a constructor vs. passing at least one parameter to a
> constructor.
>
>
>> and be usable in all cases of initialization.
>>
>> Therefore, if the feature can't be used everywhere, then it's not living
>> up to its intended purpose: to universally replace all initialization. The
>> purpose of this feature is to make uniform initialization usable in all
>> contexts, so that C++ programmers don't have to go "well, sometimes we use
>> {} to initialize, but you can't trust it so most of the time you use (),
>> except when your compiler thinks it's a function so you use {} again, but
>> not when..."
>>
>
> And you want to add *three more* ways and *four more* cryptic syntaxes to
> do initialization:
>
>>
>> - "l": Only look at initializer_list constructors.
>> - "c": Only look at non-initializer_list constructors.
>> - "lc": Look at initializer_list constructors first. Equivalent to {}.
>> - "cl": Look at non-initializer_list constructors first.
>>
>> I'm not sure how these are cryptic. They are all slight variations of the
same thing.
And if it's really a problem, we could drop {lc:} and {cl:}. {c:} and {l:}
are the main focus: constructors vs. list.
>> It makes the language simpler to use.
>>
>
> Given that most people read code far more often than they write it, I just
> don't see how having to learn the subtleties of *seven* (the seventh being
> value initialization vs. default initialization) different syntaxes is
> simplier than learning just three.
>
> "Uniform" is supposed to mean *one*, not *seven*. I agree that the
> standard doesn't quite achieve it, but this proposal doesn't either.
>
This proposal only has 1 method of initialization, with 4 modifiers on the
behavior of it. And the modifiers are pretty obvious.
{} is not "perfectly forwardable" as it currently stands either. A
>> braced-init-list cannot be used in a parameter pack or any other template
>> deduction contexts.
>>
>> It's a problem before this proposal and it remains one after. It's not a
>> problem this proposal is intended to solve.
>>
>
> So we'll need even *more* syntaxes to solve other related issues? What
> happened to simpler?
>
I don't know how the initialization forwarding problem will be solved, but
there's no reason it would need new initialization syntax to be solvable.
In any case, what happened was someone decided to make {lc:} the default
for {}, so that they could type as many braces for `std::vector` as for
`std::array` and `Type[]`. In effect, someone wanted brace elision for
uniform initialization. As stated in the proposal, the ideal solution would
have been to make {c:} behavior be the default, thus forcing you to use
multiple braces if you wanted a list:
std::vector<int> v1{20}; //Doesn't call an initializer_list constructor.
std::vector<int> v2{20, 30, 40}; //Compiler error. No constructor takes 3
ints
std::vector<int> v3{{20, 30, 40}}; //Makes a list
That way, you could always access any constructor via uniform
initialization. They didn't do that, and it's too late to fix that now.
There are no "simpler" solutions to the problem. Therefore, I picked the
second best solution: allow the user to state which behavior they want out
of a particular braced-init-list.
--
------=_Part_264_6609050.1357672482571
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Tuesday, January 8, 2013 7:57:16 AM UTC-8, Nevin ":-)" Liber wro=
te:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;">On 8 January 2013 03:35, Ni=
col Bolas <span dir=3D"ltr"><<a href=3D"javascript:" target=3D"_blank" g=
df-obfuscated-mailto=3D"MpBS0xdvph0J">jmck...@gmail.com</a>></span> wrot=
e:<br><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D=
"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div><br>If the above compiles, then clearly the <i>design</i> of the =
feature is to be usable for <i>more</i>
than just aggregate and list initialization. It's there to solve the=20
Most Vexing Parse issue</div></div></blockquote><div><br>How does {} not so=
lve the most vexing parse issue?</div></div></blockquote><div><br>Because y=
ou <i>can't use it everywhere</i>. As pointed out in the proposal, the shad=
owing effect of {}'s constructor picking rules means that there's no way to=
call certain constructors with {}.<br><br>Since you have to default to (),=
you'll still get the MVP. The most {} does for you in those cases is that =
you can use {} to initialize something in those specific cases. For spot fi=
xes. Then again, you could usually wrap the type in parenthesis to achieve =
the same effect.<br><br>Without the ability to freely use {} syntax everywh=
ere, it doesn't really solve the problem.<br> </div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><div class=3D"gmail_quote"><div> And at t=
he call site, I don't see how anyone can mix up passing no parameters to a =
constructor vs. passing at least one parameter to a constructor.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bo=
rder-left:1px #ccc solid;padding-left:1ex"><div><div> and be usable in all =
cases of initialization.<br><br>Therefore, if the feature can't be used eve=
rywhere, then it's not living up to its intended purpose: to universally re=
place all initialization. The
purpose of this feature is to make uniform initialization usable in all
contexts, so that C++ programmers don't have to go "well, sometimes we=20
use {} to initialize, but you can't trust it so most of the time you use
(), except when your compiler thinks it's a function so you use {}=20
again, but not when..."<br></div></div></blockquote><div><br>And you want t=
o add *three more* ways and *four more* cryptic syntaxes to do initializati=
on:<br><blockquote style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid =
rgb(204,204,204);padding-left:1ex" class=3D"gmail_quote">
<ul><li>"l": Only look at initializer_list constructors.</li><li>"c": Only =
look at non-initializer_list constructors.</li><li>"lc": Look at initialize=
r_list constructors first. Equivalent to {}.<br>
</li><li>"cl": Look at non-initializer_list constructors first.</li></ul></=
blockquote></div></div></blockquote><div>I'm not sure how these are cryptic=
.. They are all slight variations of the same thing.<br><br>And if it's real=
ly a problem, we could drop {lc:} and {cl:}. {c:} and {l:} are the main foc=
us: constructors vs. list.<br><br></div><blockquote class=3D"gmail_quote" s=
tyle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-le=
ft: 1ex;"><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>
<div><br>It makes the language simpler to use.<br></div></div></blockquote>=
<div><br>Given that most people read code far more often than they write it=
, I just don't see how having to learn the subtleties of *seven* (the seven=
th being value initialization vs. default initialization) different syntaxe=
s is simplier than learning just three.<br>
<br>"Uniform" is supposed to mean *one*, not *seven*. I agree that th=
e standard doesn't quite achieve it, but this proposal doesn't either.<br><=
/div></div></blockquote><div><br>This proposal only has 1 method of initial=
ization, with 4 modifiers on the behavior of it. And the modifiers are pret=
ty obvious.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin:=
0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div =
class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"margin:0 0=
0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>{} is not "perfectly forwardable" as it currently stands either. A bra=
ced-init-list cannot be used in a parameter pack or any other template dedu=
ction contexts.<br><br>It's a problem before this proposal and it remains o=
ne after. It's not a problem this proposal is intended to solve.<br>
</div></blockquote><div><br>So we'll need even *more* syntaxes to solve oth=
er related issues? What happened to simpler?</div></div></blockquote>=
<div><br>I don't know how the initialization forwarding problem will be sol=
ved, but there's no reason it would need new initialization syntax to be so=
lvable.<br><br>In any case, what happened was someone decided to make {lc:}=
the default for {}, so that they could type as many braces for `std::vecto=
r` as for `std::array` and `Type[]`. In effect, someone wanted brace elisio=
n for uniform initialization. As stated in the proposal, the ideal solution=
would have been to make {c:} behavior be the default, thus forcing you to =
use multiple braces if you wanted a list:<br><br><div class=3D"prettyprint"=
style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187,=
187); border-style: solid; border-width: 1px; word-wrap: break-word;"><cod=
e class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color:=
#000;" class=3D"styled-by-prettify">std</span><span style=3D"color: #660;"=
class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">vector</span><span style=3D"color: #080;" class=3D"=
styled-by-prettify"><int></span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> v1</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">{</span><span style=3D"color: #066;" class=3D"styled-by-prett=
ify">20</span><span style=3D"color: #660;" class=3D"styled-by-prettify">};<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an style=3D"color: #800;" class=3D"styled-by-prettify">//Doesn't call an in=
itializer_list constructor.</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br>std</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify">vector</span><span style=3D"color: #080;" class=3D"styled-by-prettify=
"><int></span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> v2</span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</s=
pan><span style=3D"color: #066;" class=3D"styled-by-prettify">20</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #066;" class=3D"styled-by-prettify">30</span><span style=3D"color: #660;"=
class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"styled-b=
y-prettify">40</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">};</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </s=
pan><span style=3D"color: #800;" class=3D"styled-by-prettify">//Compiler er=
ror. No constructor takes 3 ints</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>std</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify">vector</span><span style=3D"color: #080;" class=3D"styled-by-p=
rettify"><int></span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> v3</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">{{</span><span style=3D"color: #066;" class=3D"styled-by-prettify">20</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D=
"color: #066;" class=3D"styled-by-prettify">30</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"st=
yled-by-prettify">40</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">}};</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> </span><span style=3D"color: #800;" class=3D"styled-by-prettify">//Make=
s a list</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><b=
r></span></div></code></div><br>That way, you could always access any const=
ructor via uniform initialization. They didn't do that, and it's too late t=
o fix that now. There are no "simpler" solutions to the problem. Therefore,=
I picked the second best solution: allow the user to state which behavior =
they want out of a particular braced-init-list.<br><br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_264_6609050.1357672482571--
.
Author: Nevin Liber <nevin@eviloverlord.com>
Date: Tue, 8 Jan 2013 13:42:23 -0600
Raw View
--0015175d078268af3004d2cc2751
Content-Type: text/plain; charset=ISO-8859-1
On 8 January 2013 13:14, Nicol Bolas <jmckesson@gmail.com> wrote:
>
>
> On Tuesday, January 8, 2013 7:57:16 AM UTC-8, Nevin ":-)" Liber wrote:
>
>> On 8 January 2013 03:35, Nicol Bolas <jmck...@gmail.com> wrote:
>>
>>>
>>> If the above compiles, then clearly the *design* of the feature is to
>>> be usable for *more* than just aggregate and list initialization. It's
>>> there to solve the Most Vexing Parse issue
>>>
>>
>> How does {} not solve the most vexing parse issue?
>>
>
> Because you *can't use it everywhere*.
>
Why can't I use it everywhere where I pass *zero* parameters?
> As pointed out in the proposal, the shadowing effect of {}'s constructor
> picking rules means that there's no way to call certain constructors with
> {}.
>
And your proposal still doesn't fix that in 100% of the cases. Take the
following class:
struct S {
S();
S(initializer_list<int>);
S(initializer_list<double>);
};
How do I call S(initializer_list<int>) with your proposed solutions on a 0
element initializer list?
And I still don't understand why I'd want to design a class where S() vs.
S{} vs. S{{}} results in different objects; seems very fragile to me.
I'm with Jeffery on this one. -1 for the proposal, and barring new
information, I probably won't comment on it anymore unless someone presents
it in EWG.
--
Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404
--
--0015175d078268af3004d2cc2751
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br><div class=3D"gmail_quote">On 8 January 2013 13:14, Nicol Bolas <sp=
an dir=3D"ltr"><<a href=3D"mailto:jmckesson@gmail.com" target=3D"_blank"=
>jmckesson@gmail.com</a>></span> wrote:<br><blockquote class=3D"gmail_qu=
ote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex=
">
<br><br>On Tuesday, January 8, 2013 7:57:16 AM UTC-8, Nevin ":-)"=
Liber wrote:<div><blockquote class=3D"gmail_quote" style=3D"margin:0;margi=
n-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex">On 8 January 2013=
03:35, Nicol Bolas <span dir=3D"ltr"><<a>jmck...@gmail.com</a>></spa=
n> wrote:<br>
<div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"margi=
n:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div><br>If the above compiles, then clearly the <i>design</i> of the =
feature is to be usable for <i>more</i>
than just aggregate and list initialization. It's there to solve the=
=20
Most Vexing Parse issue</div></div></blockquote><div><br>How does {} not so=
lve the most vexing parse issue?</div></div></blockquote></div><div><br>Bec=
ause you <i>can't use it everywhere</i>.</div></blockquote><div><br>
</div><div>Why can't I use it everywhere where I pass *zero* parameters=
?</div><div>=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 =
0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div> As pointed out in=
the proposal, the shadowing effect of {}'s constructor picking rules m=
eans that there's no way to call certain constructors with {}.<br>
</div></blockquote><div><br></div><div>And your proposal still doesn't =
fix that in 100% of the cases. =A0Take the following class:</div><div><br><=
/div><div>struct S {</div><div>=A0 =A0 S();</div><div>=A0 =A0 S(initializer=
_list<int>);</div>
<div>=A0 =A0 S(initializer_list<double>);</div><div>};</div><div><br>=
</div><div>How do I call S(initializer_list<int>) with your proposed =
solutions on a 0 element initializer list?</div><div><br></div><div>And I s=
till don't understand why I'd want to design a class where S() vs. =
S{} vs. S{{}} results in different objects; seems very fragile to me.</div>
<div>=A0</div><div>I'm with Jeffery on this one. -1 for the proposal, a=
nd barring new information, I probably won't comment on it anymore unle=
ss someone presents it in EWG.=A0</div></div>-- <br>=A0Nevin ":-)"=
; Liber=A0 <mailto:<a href=3D"mailto:nevin@eviloverlord.com" target=3D"_=
blank">nevin@eviloverlord.com</a>>=A0 <a href=3D"tel:%28847%29%20691-140=
4" value=3D"+18476911404" target=3D"_blank">(847) 691-1404</a>
<p></p>
-- <br />
<br />
<br />
<br />
--0015175d078268af3004d2cc2751--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 8 Jan 2013 12:01:22 -0800 (PST)
Raw View
------=_Part_1394_11222480.1357675282658
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, January 8, 2013 11:42:23 AM UTC-8, Nevin ":-)" Liber wrote:
>
>
>
> On 8 January 2013 13:14, Nicol Bolas <jmck...@gmail.com <javascript:>>wrote:
>
>>
>>
>> On Tuesday, January 8, 2013 7:57:16 AM UTC-8, Nevin ":-)" Liber wrote:
>>
>>> On 8 January 2013 03:35, Nicol Bolas <jmck...@gmail.com> wrote:
>>>
>>>>
>>>> If the above compiles, then clearly the *design* of the feature is to
>>>> be usable for *more* than just aggregate and list initialization. It's
>>>> there to solve the Most Vexing Parse issue
>>>>
>>>
>>> How does {} not solve the most vexing parse issue?
>>>
>>
>> Because you *can't use it everywhere*.
>>
>
> Why can't I use it everywhere where I pass *zero* parameters?
>
Are you telling me that 8.5.4 all of the other language in the standard
around braced-init-lists exists for the *sole purpose* of being able to say
"default construct T?"
>
>
>> As pointed out in the proposal, the shadowing effect of {}'s constructor
>> picking rules means that there's no way to call certain constructors with
>> {}.
>>
>
> And your proposal still doesn't fix that in 100% of the cases. Take the
> following class:
>
> struct S {
> S();
> S(initializer_list<int>);
> S(initializer_list<double>);
> };
>
> How do I call S(initializer_list<int>) with your proposed solutions on a 0
> element initializer list?
>
I'm not entirely sure about how the rules of overload resolution work in
this case, but I think that using S{l:0} will use the integer version, and
S{l: 0.0} will use the double-precision version.
> And I still don't understand why I'd want to design a class where S() vs.
> S{} vs. S{{}} results in different objects; seems very fragile to me.
>
I'm confused. The standard is quite clear that an empty braced-init-list
will result in calling the default constructor, in all cases. The only
place where there's a difference is the latter case, and that one makes
perfect sense. You're not saying "create an empty `S`". You're saying
"Create an `S` that takes one parameter, which is a default constructed
argument who's type will be deduced based on the available single-parameter
constructors on `S`."
Those are two different things, so they *should* result in different
objects. In uniform initialization, {} doesn't mean "do nothing"; {} aren't
*lists*; they're initializers. It means "initialize an object of a type
determined by context."
--
------=_Part_1394_11222480.1357675282658
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Tuesday, January 8, 2013 11:42:23 AM UTC-8, Nevin ":-)" Liber wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;"><br><br><div class=3D"gmai=
l_quote">On 8 January 2013 13:14, Nicol Bolas <span dir=3D"ltr"><<a href=
=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"vwfYSV20ciAJ">j=
mck...@gmail.com</a>></span> wrote:<br><blockquote class=3D"gmail_quote"=
style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br><br>On Tuesday, January 8, 2013 7:57:16 AM UTC-8, Nevin ":-)" Liber wro=
te:<div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8=
ex;border-left:1px #ccc solid;padding-left:1ex">On 8 January 2013 03:35, Ni=
col Bolas <span dir=3D"ltr"><<a>jmck...@gmail.com</a>></span> wrote:<=
br>
<div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"margi=
n:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div><br>If the above compiles, then clearly the <i>design</i> of the =
feature is to be usable for <i>more</i>
than just aggregate and list initialization. It's there to solve the=20
Most Vexing Parse issue</div></div></blockquote><div><br>How does {} not so=
lve the most vexing parse issue?</div></div></blockquote></div><div><br>Bec=
ause you <i>can't use it everywhere</i>.</div></blockquote><div><br>
</div><div>Why can't I use it everywhere where I pass *zero* parameters?</d=
iv></div></blockquote><div><br>Are you telling me that 8.5.4 all of the oth=
er language in the standard around braced-init-lists exists for the <i>sole=
purpose</i> of being able to say "default construct T?"<br> </div><bl=
ockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border=
-left: 1px #ccc solid;padding-left: 1ex;"><div class=3D"gmail_quote"><div>&=
nbsp;</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bor=
der-left:1px #ccc solid;padding-left:1ex"><div> As pointed out in the propo=
sal, the shadowing effect of {}'s constructor picking rules means that ther=
e's no way to call certain constructors with {}.<br>
</div></blockquote><div><br></div><div>And your proposal still doesn't fix =
that in 100% of the cases. Take the following class:</div><div><br></=
div><div>struct S {</div><div> S();</div><div> S(=
initializer_list<int>);</div>
<div> S(initializer_list<double>);</div><div>};</div><di=
v><br></div><div>How do I call S(initializer_list<int>) with your pro=
posed solutions on a 0 element initializer list?</div></div></blockquote><d=
iv><br>I'm not entirely sure about how the rules of overload resolution wor=
k in this case, but I think that using S{l:0} will use the integer version,=
and S{l: 0.0} will use the double-precision version.<br> </div><block=
quote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-le=
ft: 1px #ccc solid;padding-left: 1ex;"><div class=3D"gmail_quote"><div></di=
v><div>And I still don't understand why I'd want to design a class where S(=
) vs. S{} vs. S{{}} results in different objects; seems very fragile to me.=
</div></div></blockquote><div><br>I'm confused. The standard is quite clear=
that an empty braced-init-list will result in calling the default construc=
tor, in all cases. The only place where there's a difference is the latter =
case, and that one makes perfect sense. You're not saying "create an empty =
`S`". You're saying "Create an `S` that takes one parameter, which is a def=
ault constructed argument who's type will be deduced based on the available=
single-parameter constructors on `S`."<br><br>Those are two different thin=
gs, so they <i>should</i> result in different objects. In uniform initializ=
ation, {} doesn't mean "do nothing"; {} aren't <i>lists</i>; they're initia=
lizers. It means "initialize an object of a type determined by context."</d=
iv><br>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1394_11222480.1357675282658--
.
Author: vattilah-groups@yahoo.co.uk
Date: Fri, 25 Jan 2013 15:11:15 -0800 (PST)
Raw View
------=_Part_451_16076601.1359155475160
Content-Type: text/plain; charset=ISO-8859-1
Hi Nicol,
I am sympathetic to your desire to address this issue, especially the
constructor selection surprise when brace-initialization is involved, and
the indeterminism of the rules in a template context, where, as you point
out, the selection between a constructor taking an initializer_list and
ordinary constructors depends on the argument type. But, like other
respondents in this discussion, I do not like the added complexity and
syntax that your solution proposes.
My main interest, as discussed in this post, is in fixing the surprise and
indeterminism mentioned; not make initialization more uniform (although I
touch on the latter at the end). I apologise if you consider this a further
diversion of the primary aim of your proposal.
I haven't studied the issue closely, but my immediate alternative proposal
is to no longer prefer the constructor taking initializer_list where there
are viable ordinary constructors. The compiler should simply treat it as
ambiguous and refuse it.
This solution would change the mentioned surprise and indeterminism into
straight-forward ambiguity. As always, ambiguity in constructor overload
resolution is a class design issue. In other words, this solution
acknowledges that std::vector has a slight flaw in its design, and revokes
the special rule that tries to paint over it.
A change of the initializer_list preference rule will of course break (some
new C++11) code, although this may be acceptable if there is a simple way
to disambiguate.
Example:
vector <int> a {42}; // Error: Constructor selection is ambiguous under the
proposed rule change.
Existing ways to disambiguate:
vector <int> a (42); // OK: Pass size.
vector <int> a ({42}); // OK: Pass single element.
An alternative way to disambiguate in favour of initializer_list may be to
use a trailing comma:
vector <int> a {42,}; // OK: Pass single element.
This solution requires no new syntax, but lacks a way to disambiguate in
favour of ordinary constructors when using brace-initialization. My gut
feeling is that any additional syntax to improve on this issue should be
considered in a broader context, e.g. in conjunction with *named arguments*:
vector <int> a {size := 42}; // OK: Pass size.
You could even allow an unnamed argument in this case:
vector <int> a {:= 42}; // OK: Pass size.
Regards,
Vidar Hasfjord
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To post to this group, send email to std-proposals@isocpp.org.
To unsubscribe from this group, send email to std-proposals+unsubscribe@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_451_16076601.1359155475160
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div style=3D"margin-bottom: 0cm;" class=3D"western">Hi Nicol,</div><div st=
yle=3D"margin-bottom: 0cm;" class=3D"western"> </div>
<div style=3D"margin-bottom: 0cm;" class=3D"western">I am sympathetic to
your desire to address this issue, especially the constructor
selection surprise when brace-initialization is involved, and the
indeterminism of the rules in a template context, where, as you point
out, the selection between a constructor taking an initializer_list
and ordinary constructors depends on the argument type. But, like
other respondents in this discussion, I do not like the added
complexity and syntax that your solution proposes.</div><div style=3D"margi=
n-bottom: 0cm;" class=3D"western"><br>
My main interest, as
discussed in this post, is in fixing the surprise and indeterminism
mentioned; not make initialization more uniform (although I touch on
the latter at the end). I apologise if you consider this a further
diversion of the primary aim of your proposal.</div><div style=3D"margin-bo=
ttom: 0cm;" class=3D"western"><br>
I haven't studied the
issue closely, but my immediate alternative proposal is to no longer
prefer the constructor taking initializer_list where there are viable
ordinary constructors. The compiler should simply treat it as
ambiguous and refuse it.</div><div style=3D"margin-bottom: 0cm;" class=3D"w=
estern"><br>
This solution would
change the mentioned surprise and indeterminism into straight-forward
ambiguity. As always, ambiguity in constructor overload resolution is
a class design issue. In other words, this solution acknowledges that
std::vector has a slight flaw in its design, and revokes the special
rule that tries to paint over it.</div><div style=3D"margin-bottom: 0cm;" c=
lass=3D"western"><br>
A change of the
initializer_list preference rule will of course break (some new
C++11) code, although this may be acceptable if there is a simple way
to disambiguate.</div><div style=3D"margin-bottom: 0cm;" class=3D"western">=
<br>
Example:</div><div style=3D"margin-bottom: 0cm;" class=3D"western"><br>
vector <int> a
{42}; // Error: Constructor selection is ambiguous under the proposed
rule change.</div><div style=3D"margin-bottom: 0cm;" class=3D"western"><br>
Existing ways to
disambiguate:</div><div style=3D"margin-bottom: 0cm;" class=3D"western"><br=
>
vector <int> a
(42); // OK: Pass size.</div>
<div style=3D"margin-bottom: 0cm;" class=3D"western">vector <int> a
({42}); // OK: Pass single element.</div><div style=3D"margin-bottom: 0cm;"=
class=3D"western"><br>
An alternative way to
disambiguate in favour of initializer_list may be to use a trailing
comma:</div><div style=3D"margin-bottom: 0cm;" class=3D"western"><br>
vector <int> a
{42,}; // OK: Pass single element.</div><div style=3D"margin-bottom: 0cm;" =
class=3D"western"><br>
This solution requires
no new syntax, but lacks a way to disambiguate in favour of ordinary
constructors when using brace-initialization. My gut feeling is that
any additional syntax to improve on this issue should be considered
in a broader context, e.g. in conjunction with <i>named arguments</i>:</div=
><div style=3D"margin-bottom: 0cm;" class=3D"western"><br>
vector <int> a
{size :=3D 42}; // OK: Pass size.</div><div style=3D"margin-bottom: 0cm;" c=
lass=3D"western"> </div><div style=3D"margin-bottom: 0cm;" class=3D"we=
stern">You could even allow an unnamed argument in this case:</div><di=
v style=3D"margin-bottom: 0cm;" class=3D"western"> </div><div style=3D=
"margin-bottom: 0cm;" class=3D"western">vector <int> a {:=3D 42}; // =
OK: Pass size.</div><div style=3D"margin-bottom: 0cm;" class=3D"western">&n=
bsp;</div><div style=3D"margin-bottom: 0cm;" class=3D"western">Regards,</di=
v>
<p style=3D"margin-bottom: 0cm;" class=3D"western">Vidar Hasfjord</p>
<p style=3D"margin-bottom: 0cm;" class=3D"western"> </p>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
To unsubscribe from this group, send email to std-proposals+unsubscribe@iso=
cpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_451_16076601.1359155475160--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Fri, 25 Jan 2013 18:59:06 -0800 (PST)
Raw View
------=_Part_414_407501.1359169146477
Content-Type: text/plain; charset=ISO-8859-1
On Friday, January 25, 2013 3:11:15 PM UTC-8, vattila...@yahoo.co.uk wrote:
>
> Hi Nicol,
>
> I am sympathetic to your desire to address this issue, especially the
> constructor selection surprise when brace-initialization is involved, and
> the indeterminism of the rules in a template context, where, as you point
> out, the selection between a constructor taking an initializer_list and
> ordinary constructors depends on the argument type. But, like other
> respondents in this discussion, I do not like the added complexity and
> syntax that your solution proposes.
>
> My main interest, as discussed in this post, is in fixing the surprise and
> indeterminism mentioned; not make initialization more uniform (although I
> touch on the latter at the end). I apologise if you consider this a further
> diversion of the primary aim of your proposal.
>
> I haven't studied the issue closely, but my immediate alternative proposal
> is to no longer prefer the constructor taking initializer_list where there
> are viable ordinary constructors. The compiler should simply treat it as
> ambiguous and refuse it.
>
> This solution would change the mentioned surprise and indeterminism into
> straight-forward ambiguity. As always, ambiguity in constructor overload
> resolution is a class design issue. In other words, this solution
> acknowledges that std::vector has a slight flaw in its design, and revokes
> the special rule that tries to paint over it.
>
I don't like this solution, because it doesn't really solve anything. It
forces class designers to have to design around this ambiguity. Which means
everyone is going to come up with their own, completely incompatible
solutions to a problem.
Language problems should have language solutions, not library solutions.
Making everyone implement incompatible changes to their constructor
interfaces just because we don't want to make initialization *slightly*more complex is not the way to go.
Template code with your method is still unable to yoke the benefits of {}
syntax, because it can't be sure that {} will do the right thing. You can't
initialize aggregates with (), so there's no way to write a template
function that could take an aggregate or a non-aggregate class and
initialize them with the same syntax. You'd have to do some `static if` or
`std::enable_if` stuff to test the type and pick one vs. the other.
Honestly, I'm of the opinion that, if we can't fix uniform initialization
syntax to actually be *uniform* and functionally replace all other
initialization *everywhere*, then we should just deprecate and remove it
ASAP.
A change of the initializer_list preference rule will of course break (some
> new C++11) code, although this may be acceptable if there is a simple way
> to disambiguate.
>
> Example:
>
> vector <int> a {42}; // Error: Constructor selection is ambiguous under
> the proposed rule change.
>
>
> Existing ways to disambiguate:
>
> vector <int> a (42); // OK: Pass size.
> vector <int> a ({42}); // OK: Pass single element.
>
> An alternative way to disambiguate in favour of initializer_list may be to
> use a trailing comma:
>
> vector <int> a {42,}; // OK: Pass single element.
>
> This solution requires no new syntax, but lacks a way to disambiguate in
> favour of ordinary constructors when using brace-initialization.
>
And disambiguation in favor of constructors is the most important feature.
It's what allows you to always use {} initialization on anything, thus
achieving uniform initialization and consistent results.
My gut feeling is that any additional syntax to improve on this issue
> should be considered in a broader context, e.g. in conjunction with *named
> arguments*:
>
> vector <int> a {size := 42}; // OK: Pass size.
>
My gut feeling is that named arguments are a bad idea in a language that
doesn't require argument names or even *consistent* argument names between
the function declaration and definition. Let alone issues with
function/member pointers. So I don't buy that this "broader context" is
something that should be considered, regardless of uniform initialization.
How would you use this in a template concept? How would you use it for
initializing some type T, which may or many not have a constructor
parameter named `size`? Most important of all, how would this work with *
aggregates*; remember, this is supposed to be *uniform* initialization.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_414_407501.1359169146477
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Friday, January 25, 2013 3:11:15 PM UTC-8, vattila...@yahoo.co.u=
k wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0=
..8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<div style=3D"margin-bottom:0cm">Hi Nicol,</div><div style=3D"margin-bottom=
:0cm"> </div>
<div style=3D"margin-bottom:0cm">I am sympathetic to
your desire to address this issue, especially the constructor
selection surprise when brace-initialization is involved, and the
indeterminism of the rules in a template context, where, as you point
out, the selection between a constructor taking an initializer_list
and ordinary constructors depends on the argument type. But, like
other respondents in this discussion, I do not like the added
complexity and syntax that your solution proposes.</div><div style=3D"margi=
n-bottom:0cm"><br>
My main interest, as
discussed in this post, is in fixing the surprise and indeterminism
mentioned; not make initialization more uniform (although I touch on
the latter at the end). I apologise if you consider this a further
diversion of the primary aim of your proposal.</div><div style=3D"margin-bo=
ttom:0cm"><br>
I haven't studied the
issue closely, but my immediate alternative proposal is to no longer
prefer the constructor taking initializer_list where there are viable
ordinary constructors. The compiler should simply treat it as
ambiguous and refuse it.</div><div style=3D"margin-bottom:0cm"><br>
This solution would
change the mentioned surprise and indeterminism into straight-forward
ambiguity. As always, ambiguity in constructor overload resolution is
a class design issue. In other words, this solution acknowledges that
std::vector has a slight flaw in its design, and revokes the special
rule that tries to paint over it.</div></blockquote><div><br>I don't like t=
his solution, because it doesn't really solve anything. It forces class des=
igners to have to design around this ambiguity. Which means everyone is goi=
ng to come up with their own, completely incompatible solutions to a proble=
m.<br><br>Language problems should have language solutions, not library sol=
utions. Making everyone implement incompatible changes to their constructor=
interfaces just because we don't want to make initialization <i>slightly</=
i> more complex is not the way to go.<br><br>Template code with your method=
is still unable to yoke the benefits of {} syntax, because it can't be sur=
e that {} will do the right thing. You can't initialize aggregates with (),=
so there's no way to write a template function that could take an aggregat=
e or a non-aggregate class and initialize them with the same syntax. You'd =
have to do some `static if` or `std::enable_if` stuff to test the type and =
pick one vs. the other.<br><br>Honestly, I'm of the opinion that, if we can=
't fix uniform initialization syntax to actually be <i>uniform</i> and func=
tionally replace all other initialization <i>everywhere</i>, then we should=
just deprecate and remove it ASAP.<br><br></div><blockquote class=3D"gmail=
_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;p=
adding-left: 1ex;"><div style=3D"margin-bottom:0cm">
A change of the
initializer_list preference rule will of course break (some new
C++11) code, although this may be acceptable if there is a simple way
to disambiguate.</div><div style=3D"margin-bottom:0cm"><br>
Example:</div><div><br>
vector <int> a
{42}; // Error: Constructor selection is ambiguous under the proposed
rule change.<br> </div></blockquote><blockquote class=3D"gmail_quote" =
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-l=
eft: 1ex;"><div style=3D"margin-bottom:0cm"><br>
Existing ways to
disambiguate:</div><div style=3D"margin-bottom:0cm"><br>
vector <int> a
(42); // OK: Pass size.</div>
<div style=3D"margin-bottom:0cm">vector <int> a
({42}); // OK: Pass single element.</div><div style=3D"margin-bottom:0cm"><=
br>
An alternative way to
disambiguate in favour of initializer_list may be to use a trailing
comma:</div><div style=3D"margin-bottom:0cm"><br>
vector <int> a
{42,}; // OK: Pass single element.</div><div style=3D"margin-bottom:0cm"><b=
r>
This solution requires
no new syntax, but lacks a way to disambiguate in favour of ordinary
constructors when using brace-initialization.</div></blockquote><div><br>An=
d disambiguation in favor of constructors is the most important feature. It=
's what allows you to always use {} initialization on anything, thus achiev=
ing uniform initialization and consistent results.<br><br></div><blockquote=
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1=
px #ccc solid;padding-left: 1ex;"><div style=3D"margin-bottom:0cm">My gut f=
eeling is that
any additional syntax to improve on this issue should be considered
in a broader context, e.g. in conjunction with <i>named arguments</i>:</div=
><div style=3D"margin-bottom:0cm"><br>
vector <int> a
{size :=3D 42}; // OK: Pass size.</div></blockquote><div><br>My gut feeling=
is that named arguments are a bad idea in a language that doesn't require =
argument names or even <i>consistent</i> argument names between the functio=
n declaration and definition. Let alone issues with function/member pointer=
s. So I don't buy that this "broader context" is something that should be c=
onsidered, regardless of uniform initialization.<br><br>How would you use t=
his in a template concept? How would you use it for initializing some type =
T, which may or many not have a constructor parameter named `size`? Most im=
portant of all, how would this work with <i>aggregates</i>; remember, this =
is supposed to be <i>uniform</i> initialization.</div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_414_407501.1359169146477--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Sat, 26 Jan 2013 00:54:51 -0800 (PST)
Raw View
------=_Part_543_17390412.1359190491982
Content-Type: text/plain; charset=ISO-8859-1
On Saturday, January 26, 2013 3:11:15 AM UTC+4, vattila...@yahoo.co.uk
wrote:
>
>
> Existing ways to disambiguate:
>
> vector <int> a (42); // OK: Pass size.
> vector <int> a ({42}); // OK: Pass single element.
>
For the latter initialization there are two viable constructors:
explicit vector(size_type n);
vector(initializer_list<T>, const Allocator& = Allocator());
The following code
std::vector<int *> v({42});
std::cout << v.size() << std::endl;
will print 42.
An alternative way to disambiguate in favour of initializer_list may be to
> use a trailing comma:
>
> vector <int> a {42,}; // OK: Pass single element.
>
Again, the following initialization
std::vector<int *> a{42,};
is allowed under the current rules.
My gut feeling is that any additional syntax to improve on this issue
> should be considered in a broader context
>
That's my feeling too. Initializer lists with expression semantics could
solve ambiguity issues and forwarding issues simultaneously.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To post to this group, send email to std-proposals@isocpp.org.
To unsubscribe from this group, send email to std-proposals+unsubscribe@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_543_17390412.1359190491982
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Saturday, January 26, 2013 3:11:15 AM UTC+4, vattila...@yahoo.co.uk wrot=
e:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;"><div style=3D"margin-bottom:=
0cm"><br>
Existing ways to
disambiguate:</div><div style=3D"margin-bottom:0cm"><br>
vector <int> a
(42); // OK: Pass size.</div>
<div style=3D"margin-bottom:0cm">vector <int> a
({42}); // OK: Pass single element.</div></blockquote><div><br>For the latt=
er initialization there are two viable constructors:<br><br> &nb=
sp; explicit vector(size_type n);<br> vector(initializer_=
list<T>, const Allocator& =3D Allocator());<br><br>The following =
code<br><br> std::vector<int *> v({42});<br> &=
nbsp; std::cout << v.size() << std::endl;<br><br>will pri=
nt 42.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;ma=
rgin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div style=
=3D"margin-bottom:0cm">
An alternative way to
disambiguate in favour of initializer_list may be to use a trailing
comma:</div><div style=3D"margin-bottom:0cm"><br>
vector <int> a
{42,}; // OK: Pass single element.</div></blockquote><div><br>Again, the fo=
llowing initialization<br><br> std::vector<int *> a=
{42,};<br><br>is allowed under the current rules.<br><br></div><blockquote =
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1p=
x #ccc solid;padding-left: 1ex;"><div style=3D"margin-bottom:0cm">
My gut feeling is that
any additional syntax to improve on this issue should be considered
in a broader context</div></blockquote><div><br>That's my feeling too. Init=
ializer lists with expression semantics could solve ambiguity issues and f=
orwarding issues simultaneously.<br></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
To unsubscribe from this group, send email to std-proposals+unsubscribe@iso=
cpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_543_17390412.1359190491982--
.
Author: vattilah-groups@yahoo.co.uk
Date: Sat, 26 Jan 2013 11:22:27 -0800 (PST)
Raw View
------=_Part_1184_32392751.1359228147524
Content-Type: text/plain; charset=ISO-8859-1
Hi Nicolay,
> The following code
>
> std::vector<int *> v({42});
> std::cout << v.size() << std::endl;
>
> will print 42.
>
As it should. There is no apparent ambiguity for vector <int*> {42}. The
apparent ambiguity only accurs when the element type is implicitly
convertible the type of n-parameter for the vector <T> (size_type n, const
value_type&, const allocator_type&) constructor.
> [addintional syntax should be considered in a broader context] That's my
> feeling too. Initializer lists with expression semantics could solve
> ambiguity issues and forwarding issues simultaneously.
>
Your replies was one of the reasons I came to that view. There is obviously
room to explore the design space here.
Regards,
Vidar Hasfjord
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To post to this group, send email to std-proposals@isocpp.org.
To unsubscribe from this group, send email to std-proposals+unsubscribe@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_1184_32392751.1359228147524
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div>Hi Nicolay,</div><div> </div><blockquote style=3D"margin: 0px 0px=
0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204); borde=
r-left-width: 1px; border-left-style: solid;" class=3D"gmail_quote"><div>Th=
e following code<br><br> std::vector<int *> v({42})=
;<br> std::cout << v.size() << std::endl;<br>=
<br>will print 42.</div></blockquote><div> </div><div>As it should. Th=
ere is no apparent ambiguity for vector <int*> {42}. The apparent amb=
iguity only accurs when the element type is implicitly convertible the type=
of n-parameter for the vector <T> (size_type n, const value_typ=
e&, const allocator_type&) constructor.</div><div> </div><bloc=
kquote style=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-c=
olor: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid;=
" class=3D"gmail_quote"><div>[addintional syntax should be considered in a =
broader context] That's my feeling too. Initializer lists with expression s=
emantics could solve ambiguity issues and forwarding issues simultaneously=
..</div></blockquote><div> </div><div>Your replies was one of the reaso=
ns I came to that view. There is obviously room to explore the design space=
here.</div><div> </div><div><div>Regards,</div><div>Vidar Hasfjord</d=
iv><div> </div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
To unsubscribe from this group, send email to std-proposals+unsubscribe@iso=
cpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_1184_32392751.1359228147524--
.
Author: vattilah-groups@yahoo.co.uk
Date: Sat, 26 Jan 2013 11:53:48 -0800 (PST)
Raw View
------=_Part_1023_12598379.1359230028611
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Hi Nicol,
I think the strength of your proposal is the motivation part where you=20
point out, in my view, a very serious problem. The weakness of your=20
proposal is your suggested solution. The proposed rules and syntax seem to=
=20
put off many readers, as seen by much of the feedback so far, and I fear=20
that the real and serious problem may be overlooked in the process.
=20
First, let me speak up for ambiguity, since you seem to so readily dismiss=
=20
it. *Unresolved ambiguity* is a very important feature of C++. It is the=20
safety valve that makes many of the powerful features of C++ viable, such=
=20
as overloading and template specialization. The refusal to compile code=20
that has an apparent ambiguity makes it manageable to reason about C++=20
code, even in the face of complex lookup, overload resolution and template=
=20
instantiation. This feature is a corner stone of C++.
=20
The evil twin of unresolved ambiguity is *arbitrarily resolved ambiguity*.=
=20
When the language invents a rule that resolves an apparent ambiguity, the=
=20
programmer needs to know the rule and how it applies in each particular=20
case of code. This is problematic. The rule may not be intuitive in all=20
cases. Code evolves. And sometimes there may not even be enough information=
=20
in the code to determinate the meaning, until the code itself is used in a=
=20
particular case. As you point out in the motivation for your proposal, the=
=20
indeterminism of constructor selection for vector <T> {20} in a template=20
context is a poignant example. This is bad.
*The initializer_list-preference rule for constructor selection in=20
brace-initialization is an arbitrary resolution of an apparent ambiguity,=
=20
which has surprising and indeterminate effects, and therefore qualifies as=
=20
a language defect in my view. *
=20
As far as I know, the rule was solely introduced to paint over an ambiguity=
=20
problem in the standard library. But, as many have pointed out, the library=
=20
would not have this ambiguity if it had been designed with initializer_list=
=20
in mind. There are many ways to avoid this ambiguity in the library, in the=
=20
same way ambiguities in overload resolution always have been dealt with.
=20
So, I wish you well in defending your proposal, but I hope you will focus=
=20
as much on the problem as you do on your particular solution. Let me=20
suggest a two-step approach:
=20
1. Get the problem recognized as a serious language defect, and propose=20
revoking the rule that causes it.
2. Propose features to make brace-initialization more powerful, as to=20
fulfil its promise of uniform initialization.
I consider (1) most important, but let me end with some adventurous=20
brain-storming about (2). In my last post, I did briefly propose=20
piggy-backing on a hypothetical "named arguments" feature:
vector <int> a {size :=3D 42}; // OK: Pass size.
I then allowed the actual parameter name to be dropped:=20
vector <int> a {:=3D 42}; // OK: Pass size.
This then becomes bare-bones syntax to indicate that an argument should be=
=20
explicitly matched against a parameter list. Since 42 is not an=20
initializer_list, this syntax enables the disambiguation in favour of=20
ordinary constructors, while keeping the possibility open for the syntax to=
=20
be extended in the future to support named arguments. Note that this syntax=
=20
is similar to yours, and will reap the full benefit of brace-initialization=
=20
(non-narrowing, etc.).
Now, let's go crazy and allow the elision of the braces for the=20
single-argument case:
vector <int> a :=3D 42; // OK: Pass size.
Voil=E0! We have derived a new simple, intuitive and well-known syntax for=
=20
new-style non-narrowing initialization! This syntax is as intuitive and=20
simple as the old "=3D" syntax, and does not make dual use of the assignmen=
t=20
operator token "=3D", nor does it need the special copy-initialization rule=
s=20
for the "=3D" syntax.
The syntax even works well with initializer-lists:
vector <int> a :=3D {42}; // OK: Pass single element.
This works fine because it expands to an explicit argument match for an=20
initializer_list:
vector <int> a {:=3D {42}}; // OK: Pass single element.
> You can't initialize aggregates with ()
Perhaps this warrants special consideration? Is there any reason why this=
=20
should not be allowed? E.g:
struct Abc {int a, b, c;};
Abc abc (1, 2, 3);
Conceptually, the language only needs to add an implicit constructor. This=
=20
would solve the emplace_back problem you demonstrated, I presume.
> Honestly, I'm of the opinion that, if we can't fix uniform initialization=
=20
syntax to actually be *uniform* and functionally replace all other=20
initialization *everywhere*, then we should just deprecate and remove it=20
ASAP.
Well, beware of throwing out the baby with the bathwater.=20
Brace-initialization syntax solves issues other than uniformity, such as=20
narrowing and the most-vexing-parse.
Regards,
Vidar Hasfjord
=20
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To post to this group, send email to std-proposals@isocpp.org.
To unsubscribe from this group, send email to std-proposals+unsubscribe@iso=
cpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/?hl=3Den.
------=_Part_1023_12598379.1359230028611
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div style=3D"margin-bottom: 0cm;" class=3D"western">Hi Nicol,</div><div st=
yle=3D"margin-bottom: 0cm;" class=3D"western"><br>
I think the strength of
your proposal is the motivation part where you point out, in my view,
a very serious problem. The weakness of your proposal is your
suggested solution. The proposed rules and syntax seem to put off
many readers, as seen by much of the feedback so far, and I fear that
the real and serious problem may be overlooked in the process.</div><div st=
yle=3D"margin-bottom: 0cm;" class=3D"western"> </div><div style=3D"mar=
gin-bottom: 0cm;" class=3D"western">First, let me speak up
for ambiguity, since you seem to so readily dismiss it. <i>Unresolved
ambiguity</i><span style=3D"font-style: normal;"> is a very important
feature of C++. It is the safety valve that makes many of the
powerful features of C++ viable, such as overloading and template
specialization. The refusal to compile code that has an apparent
ambiguity makes it manageable to reason about C++ code, even in the
face of complex lookup, overload resolution and template
instantiation. This feature is a corner stone of C++.</span></div><div styl=
e=3D"margin-bottom: 0cm;" class=3D"western"><span style=3D"font-style: norm=
al;"></span> </div><div style=3D"margin-bottom: 0cm;" class=3D"western=
"><span style=3D"font-style: normal;"></span><span style=3D"font-style: nor=
mal;">The
evil twin of unresolved ambiguity is </span><i>arbitrarily resolved
ambiguity</i><span style=3D"font-style: normal;">. When the language
invents a rule that resolves an apparent ambiguity, the programmer
needs to know the rule and how it applies in each particular case of
code. This is problematic. The rule may not be intuitive in all
cases. Code evolves. And sometimes there may not even be enough
information in the code to determinate the meaning, until the code
itself is used in a particular case. As you point out in the
motivation for your proposal, the indeterminism of constructor
selection for vector <T> {20} in a template context is a
poignant example. This is bad.</span></div><div style=3D"margin-bottom: 0cm=
;" class=3D"western"><span style=3D"font-style: normal;"></span><br>
<strong>The
initializer_list-preference rule for constructor selection in
brace-initialization is an arbitrary resolution of an apparent
ambiguity, which has surprising and indeterminate effects, and
therefore qualifies as a <i>language defect</i><span style=3D"font-style: n=
ormal;">
in my view. </span></strong></div><div style=3D"margin-bottom: 0cm;" class=
=3D"western"><span style=3D"font-style: normal;"></span> </div><div st=
yle=3D"margin-bottom: 0cm;" class=3D"western"><span style=3D"font-style: no=
rmal;"></span><span style=3D"font-style: normal;">As
far as I know, the rule was solely introduced to paint over an
ambiguity problem in the standard library. But, as many have pointed
out, the library would not have this ambiguity if it had been
designed with initializer_list in mind. There are many ways to avoid
this ambiguity in the library, in the same way ambiguities in
overload resolution always have been dealt with.</span></div><div style=3D"=
margin-bottom: 0cm;" class=3D"western"><span style=3D"font-style: normal;">=
</span> </div><div style=3D"margin-bottom: 0cm;" class=3D"western"><sp=
an style=3D"font-style: normal;"></span><span style=3D"font-style: normal;"=
>So,
I wish you well in defending your proposal, but I hope you will focus
as much on the problem as you do on your particular solution. Let me
suggest a two-step approach:</span></div><div style=3D"margin-bottom: 0cm;"=
class=3D"western"><span style=3D"font-style: normal;"></span> </div><=
div style=3D"margin-bottom: 0cm;" class=3D"western"><span style=3D"font-sty=
le: normal;"></span><span style=3D"font-style: normal;">1.
Get the problem recognized as a serious language defect, and propose
revoking the rule that causes it.</span></div><div style=3D"margin-bottom: =
0cm;" class=3D"western"><span style=3D"font-style: normal;"></span><span st=
yle=3D"font-style: normal;">2.
Propose features to make brace-initialization more powerful, as to
fulfil its promise of uniform initialization.</span></div><div style=3D"mar=
gin-bottom: 0cm;" class=3D"western"><span style=3D"font-style: normal;"></s=
pan><br>
I consider (1) most
important, but let me end with some adventurous brain-storming about
(2). In my last post, I did briefly propose piggy-backing on a
hypothetical "named arguments" feature:</div><div style=3D"margin-bottom: 0=
cm;" class=3D"western"><br>
vector <int> a
{size :=3D 42}; // OK: Pass size.</div><div style=3D"margin-bottom: 0cm;" c=
lass=3D"western"><br>
I then allowed the
actual parameter name to be dropped:=20
</div><div style=3D"margin-bottom: 0cm;" class=3D"western"><br>
vector <int> a
{:=3D 42}; // OK: Pass size.</div><div style=3D"margin-bottom: 0cm;" class=
=3D"western"><br>
This then becomes
bare-bones syntax to indicate that an argument should be explicitly
matched against a parameter list. Since 42 is not an
initializer_list, this syntax enables the disambiguation in favour of
ordinary constructors, while keeping the possibility open for the
syntax to be extended in the future to support named arguments. Note
that this syntax is similar to yours, and will reap the full benefit
of brace-initialization (non-narrowing, etc.).</div><div style=3D"margin-bo=
ttom: 0cm;" class=3D"western"><br>
Now, let's go crazy and
allow the elision of the braces for the single-argument case:</div><div sty=
le=3D"margin-bottom: 0cm;" class=3D"western"><br>
vector <int> a :=3D
42; // OK: Pass size.</div><div style=3D"margin-bottom: 0cm;" class=3D"west=
ern"><br>
Voil=E0! We have derived
a new simple, intuitive and well-known syntax for new-style
non-narrowing initialization! This syntax is as intuitive and simple
as the old "=3D" syntax, and does not make dual use of the
assignment operator token "=3D", nor does it need the special
copy-initialization rules for the "=3D" syntax.</div><div style=3D"margin-b=
ottom: 0cm;" class=3D"western"><br>
The syntax even works
well with initializer-lists:</div><div style=3D"margin-bottom: 0cm;" class=
=3D"western"><br>
vector <int> a :=3D
{42}; // OK: Pass single element.</div><div style=3D"margin-bottom: 0cm;" c=
lass=3D"western"><br>
This works fine because
it expands to an explicit argument match for an initializer_list:</div><div=
style=3D"margin-bottom: 0cm;" class=3D"western"><br>
vector <int> a
{:=3D {42}}; // OK: Pass single element.</div><div style=3D"margin-bottom: =
0cm;" class=3D"western"><br>
> You can't
initialize aggregates with ()</div><div style=3D"margin-bottom: 0cm;" class=
=3D"western"><br>
Perhaps this warrants
special consideration? Is there any reason why this should not be
allowed? E.g:</div><div style=3D"margin-bottom: 0cm;" class=3D"western"><br=
>
struct Abc {int a, b,
c;};</div>
<div style=3D"margin-bottom: 0cm;" class=3D"western">Abc abc (1, 2, 3);</di=
v><div style=3D"margin-bottom: 0cm;" class=3D"western"><br>
Conceptually, the
language only needs to add an implicit constructor. This would solve
the emplace_back problem you demonstrated, I presume.</div><div style=3D"ma=
rgin-bottom: 0cm;" class=3D"western"><br>
> Honestly, I'm of
the opinion that, if we can't fix uniform initialization syntax to
actually be <i>uniform</i> and functionally replace all other
initialization <i>everywhere</i>, then we should just deprecate and
remove it ASAP.</div><div style=3D"margin-bottom: 0cm;" class=3D"western"><=
br>
Well, beware of
throwing out the baby with the bathwater. Brace-initialization syntax
solves issues other than uniformity, such as narrowing and the
most-vexing-parse.</div><div style=3D"margin-bottom: 0cm;" class=3D"western=
"><br>
Regards,</div><div style=3D"margin-bottom: 0cm;" class=3D"western">Vidar Ha=
sfjord</div><div style=3D"margin-bottom: 0cm;" class=3D"western"> </di=
v>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
To unsubscribe from this group, send email to std-proposals+unsubscribe@iso=
cpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_1023_12598379.1359230028611--
.
Author: DeadMG <wolfeinstein@gmail.com>
Date: Sat, 26 Jan 2013 14:16:17 -0800 (PST)
Raw View
------=_Part_507_9876001.1359238577648
Content-Type: text/plain; charset=ISO-8859-1
Hmm. It's easy to define the ideal solution, but more difficult to see how
to reach it without breaking existing code. It should be that for
std::vector<int> { 43 }, this invokes the constructor, and you should be
forced in all situations to use a double brace if you want to
uniform-initialize with an initializer-list. Not having this available
unless the Committee wants to do a breaking change, which I expect not
since some breaks would be silent like the above case, means that we'll
have to replace uniform initialization, and I think that if that's going to
be the case that we should just go straight for the ideal. But, IMO, the
"correct" behaviour is only one- 'c'. Thus, I'd simply ditch the special
character and move to something like {^- i.e., fixed uniform
initialization. I'd also say that we should simply move to language-level
tuple support.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To post to this group, send email to std-proposals@isocpp.org.
To unsubscribe from this group, send email to std-proposals+unsubscribe@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_507_9876001.1359238577648
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Hmm. It's easy to define the ideal solution, but more difficult to see how =
to reach it without breaking existing code. It should be that for std::vect=
or<int> { 43 }, this invokes the constructor, and you should be force=
d in all situations to use a double brace if you want to uniform-initialize=
with an initializer-list. Not having this available unless the Committee w=
ants to do a breaking change, which I expect not since some breaks would be=
silent like the above case, means that we'll have to replace uniform initi=
alization, and I think that if that's going to be the case that we should j=
ust go straight for the ideal. But, IMO, the "correct" behaviour is only on=
e- 'c'. Thus, I'd simply ditch the special character and move to something =
like {^- i.e., fixed uniform initialization. I'd also say that we should si=
mply move to language-level tuple support.
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
To unsubscribe from this group, send email to std-proposals+unsubscribe@iso=
cpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_507_9876001.1359238577648--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sat, 26 Jan 2013 15:01:34 -0800 (PST)
Raw View
------=_Part_942_30438184.1359241294344
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Saturday, January 26, 2013 11:53:48 AM UTC-8, vattila...@yahoo.co.uk=20
wrote:
>
> Hi Nicol,
>
> I think the strength of your proposal is the motivation part where you=20
> point out, in my view, a very serious problem. The weakness of your=20
> proposal is your suggested solution. The proposed rules and syntax seem t=
o=20
> put off many readers, as seen by much of the feedback so far, and I fear=
=20
> that the real and serious problem may be overlooked in the process.
> =20
> First, let me speak up for ambiguity, since you seem to so readily dismis=
s=20
> it. *Unresolved ambiguity* is a very important feature of C++. It is the=
=20
> safety valve that makes many of the powerful features of C++ viable, such=
=20
> as overloading and template specialization. The refusal to compile code=
=20
> that has an apparent ambiguity makes it manageable to reason about C++=20
> code, even in the face of complex lookup, overload resolution and templat=
e=20
> instantiation. This feature is a corner stone of C++.
> =20
> The evil twin of unresolved ambiguity is *arbitrarily resolved ambiguity*=
..=20
> When the language invents a rule that resolves an apparent ambiguity, the=
=20
> programmer needs to know the rule and how it applies in each particular=
=20
> case of code. This is problematic. The rule may not be intuitive in all=
=20
> cases. Code evolves. And sometimes there may not even be enough informati=
on=20
> in the code to determinate the meaning, until the code itself is used in =
a=20
> particular case. As you point out in the motivation for your proposal, th=
e=20
> indeterminism of constructor selection for vector <T> {20} in a template=
=20
> context is a poignant example. This is bad.
>
> *The initializer_list-preference rule for constructor selection in=20
> brace-initialization is an arbitrary resolution of an apparent ambiguity,=
=20
> which has surprising and indeterminate effects, and therefore qualifies a=
s=20
> a language defect in my view. *
> =20
> As far as I know, the rule was solely introduced to paint over an=20
> ambiguity problem in the standard library. But, as many have pointed out,=
=20
> the library would not have this ambiguity if it had been designed with=20
> initializer_list in mind. There are many ways to avoid this ambiguity in=
=20
> the library, in the same way ambiguities in overload resolution always ha=
ve=20
> been dealt with.
> =20
> So, I wish you well in defending your proposal, but I hope you will focus=
=20
> as much on the problem as you do on your particular solution. Let me=20
> suggest a two-step approach:
> =20
> 1. Get the problem recognized as a serious language defect, and propose=
=20
> revoking the rule that causes it.
>
That's putting the cart before the horse. Giving the user the ability to=20
resolve the ambiguity themselves should *not* be contingent on making the=
=20
ambiguity illegal. The former is the most important thing, because that is=
=20
what allows the user to actually *solve the problem*. The latter is a nice=
=20
thing to have, but it is *only* nice if you have a real solution.
Making the ambiguity illegal should *never* happen without an already=20
approved plan to allow users to resolve the ambiguity. That's leaving=20
things in a worse state than they currently are.**
Also, it's a breaking change, thus requires far more careful consideration=
=20
than purely augmenting changes. My assumption going in is that the standard=
=20
committee is not going to make a major breaking change like that.
Lastly, if they *are* willing to make a breaking change, I would much=20
prefer they prevent the ambiguity directly by removing the competition. Let=
=20
{} mean "constructor with these arguments" for non-aggregates. It will mean=
=20
having to double-up on braces in some cases to get to the initializer_list=
=20
constructors, so you don't get brace elision. But it does let you get at=20
all the constructors you want.
If you're going to break the language, then break it in the way that leads=
=20
to the ideal solution. Don't break it and make the language more complex=20
with :=3D and what not.
2. Propose features to make brace-initialization more powerful, as to=20
> fulfil its promise of uniform initialization.
>
> I consider (1) most important, but let me end with some adventurous=20
> brain-storming about (2). In my last post, I did briefly propose=20
> piggy-backing on a hypothetical "named arguments" feature:
>
> vector <int> a {size :=3D 42}; // OK: Pass size.
>
> I then allowed the actual parameter name to be dropped:=20
>
> vector <int> a {:=3D 42}; // OK: Pass size.
>
> This then becomes bare-bones syntax to indicate that an argument should b=
e=20
> explicitly matched against a parameter list. Since 42 is not an=20
> initializer_list, this syntax enables the disambiguation in favour of=20
> ordinary constructors, while keeping the possibility open for the syntax =
to=20
> be extended in the future to support named arguments. Note that this synt=
ax=20
> is similar to yours, and will reap the full benefit of brace-initializati=
on=20
> (non-narrowing, etc.).
>
Just on quality of syntax issues, using :=3D here looks *horrible*. It look=
s=20
like you're trying to assign something. It's a syntax that only really=20
makes sense when dealing with named arguments. By taking out the argument=
=20
name, it now just looks really confusing and out of place. Even moreso if=
=20
:=3D were adopted for named arguments, because then the user expects it to =
be=20
used for named arguments**.
Now, let's go crazy and allow the elision of the braces for the=20
> single-argument case:
>
> vector <int> a :=3D 42; // OK: Pass size.
>
> Voil=E0! We have derived a new simple, intuitive and well-known syntax fo=
r=20
> new-style non-narrowing initialization! This syntax is as intuitive and=
=20
> simple as the old "=3D" syntax, and does not make dual use of the assignm=
ent=20
> operator token "=3D", nor does it need the special copy-initialization ru=
les=20
> for the "=3D" syntax.
>
You've managed to make an ugly syntax even uglier by now implying that `:=
=3D`=20
means "initialize" in some cases, where in another it means "assign to=20
named argument" where in a third it means "call constructor".
The user now has no idea what :=3D is supposed to even mean at this point.=
=20
Sometimes it gets wrapped in braces, sometimes it doesn't; sometimes a name=
=20
comes before it, sometimes it doesn't.
How is this less confusing than `{c: ...}`? At least that you can use=20
everywhere in the same way:
std::vector<int> v{c: ...};
std::vector<int> v2 =3D {c: ...}; //Well, if it weren't explicit.
std::vector<int> Func() {return {c: ...}; } //Again, if it weren't explicit=
..
Whereas your syntax would look like this:
std::vector<int> v :=3D ...; //But only if ... is one argument.
std::vector<int> v {:=3D ...}; //For multi-argument ...
std::vector<int> v2 =3D {:=3D ...}; //Why are there two =3D here?
std::vector<int> Func() {return {:=3D ...}; }
Oh, and the whole "no need for copy-initialization" part? You may want to r=
ead=20
this PDF <http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2575.pdf=
>,=20
as it is the reason the copy-list-initialization was added to uniform=20
initialization. Those reasons don't go away just because you put a `:`=20
before the equals.
The syntax even works well with initializer-lists:
>
> vector <int> a :=3D {42}; // OK: Pass single element.
>
> This works fine because it expands to an explicit argument match for an=
=20
> initializer_list:
>
> vector <int> a {:=3D {42}}; // OK: Pass single element.
>
> > You can't initialize aggregates with ()
>
> Perhaps this warrants special consideration? Is there any reason why this=
=20
> should not be allowed? E.g:
>
> struct Abc {int a, b, c;};
> Abc abc (1, 2, 3);=20
>
> Conceptually, the language only needs to add an implicit constructor. Thi=
s=20
> would solve the emplace_back problem you demonstrated, I presume.
>
If it implicitly added a constructor, it would *no longer be an aggregate*.=
=20
I would feel really uncomfortable about compilers automatically creating=20
functions like that for simple classes.
=20
> > Honestly, I'm of the opinion that, if we can't fix uniform=20
> initialization syntax to actually be *uniform* and functionally replace=
=20
> all other initialization *everywhere*, then we should just deprecate and=
=20
> remove it ASAP.
>
> Well, beware of throwing out the baby with the bathwater.=20
> Brace-initialization syntax solves issues other than uniformity, such as=
=20
> narrowing and the most-vexing-parse.
>
> =20
What good is having a solution that you can't reliably use? We can fix the=
=20
most-vexing-parse with an extra set of parenthesis when it comes up. And=20
narrowing can be lived with.
--=20
---=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/?hl=3Den.
------=_Part_942_30438184.1359241294344
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Saturday, January 26, 2013 11:53:48 AM UTC-8, vattila...@yahoo.co.uk wro=
te:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;">
<div style=3D"margin-bottom:0cm">Hi Nicol,</div><div style=3D"margin-bottom=
:0cm"><br>
I think the strength of
your proposal is the motivation part where you point out, in my view,
a very serious problem. The weakness of your proposal is your
suggested solution. The proposed rules and syntax seem to put off
many readers, as seen by much of the feedback so far, and I fear that
the real and serious problem may be overlooked in the process.</div><div st=
yle=3D"margin-bottom:0cm"> </div><div style=3D"margin-bottom:0cm">Firs=
t, let me speak up
for ambiguity, since you seem to so readily dismiss it. <i>Unresolved
ambiguity</i><span style=3D"font-style:normal"> is a very important
feature of C++. It is the safety valve that makes many of the
powerful features of C++ viable, such as overloading and template
specialization. The refusal to compile code that has an apparent
ambiguity makes it manageable to reason about C++ code, even in the
face of complex lookup, overload resolution and template
instantiation. This feature is a corner stone of C++.</span></div><div styl=
e=3D"margin-bottom:0cm"><span style=3D"font-style:normal"></span> </di=
v><div style=3D"margin-bottom:0cm"><span style=3D"font-style:normal"></span=
><span style=3D"font-style:normal">The
evil twin of unresolved ambiguity is </span><i>arbitrarily resolved
ambiguity</i><span style=3D"font-style:normal">. When the language
invents a rule that resolves an apparent ambiguity, the programmer
needs to know the rule and how it applies in each particular case of
code. This is problematic. The rule may not be intuitive in all
cases. Code evolves. And sometimes there may not even be enough
information in the code to determinate the meaning, until the code
itself is used in a particular case. As you point out in the
motivation for your proposal, the indeterminism of constructor
selection for vector <T> {20} in a template context is a
poignant example. This is bad.</span></div><div style=3D"margin-bottom:0cm"=
><span style=3D"font-style:normal"></span><br>
<b>The
initializer_list-preference rule for constructor selection in
brace-initialization is an arbitrary resolution of an apparent
ambiguity, which has surprising and indeterminate effects, and
therefore qualifies as a <i>language defect</i><span style=3D"font-style:no=
rmal">
in my view. </span></b></div><div style=3D"margin-bottom:0cm"><span style=
=3D"font-style:normal"></span> </div><div style=3D"margin-bottom:0cm">=
<span style=3D"font-style:normal"></span><span style=3D"font-style:normal">=
As
far as I know, the rule was solely introduced to paint over an
ambiguity problem in the standard library. But, as many have pointed
out, the library would not have this ambiguity if it had been
designed with initializer_list in mind. There are many ways to avoid
this ambiguity in the library, in the same way ambiguities in
overload resolution always have been dealt with.</span></div><div style=3D"=
margin-bottom:0cm"><span style=3D"font-style:normal"></span> </div><di=
v style=3D"margin-bottom:0cm"><span style=3D"font-style:normal"></span><spa=
n style=3D"font-style:normal">So,
I wish you well in defending your proposal, but I hope you will focus
as much on the problem as you do on your particular solution. Let me
suggest a two-step approach:</span></div><div style=3D"margin-bottom:0cm"><=
span style=3D"font-style:normal"></span> </div><div style=3D"margin-bo=
ttom:0cm"><span style=3D"font-style:normal"></span><span style=3D"font-styl=
e:normal">1.
Get the problem recognized as a serious language defect, and propose
revoking the rule that causes it.</span></div></blockquote><div><br>That's =
putting the cart before the horse. Giving the user the ability to resolve t=
he ambiguity themselves should <i>not</i>
be contingent on making the ambiguity illegal. The former is the most=20
important thing, because that is what allows the user to actually <i>solve =
the problem</i>. The latter is a nice thing to have, but it is <i>only</i> =
nice if you have a real solution.<br><br>Making the ambiguity illegal shoul=
d <i>never</i> happen without an already approved plan to allow users to re=
solve the ambiguity. That's leaving things in a worse state than they curre=
ntly are.<i></i><br><br>Also,
it's a breaking change, thus requires far more careful consideration=20
than purely augmenting changes. My assumption going in is that the=20
standard committee is not going to make a major breaking change like=20
that.<br><br>Lastly, if they <i>are</i> willing to make a breaking=20
change, I would much prefer they prevent the ambiguity directly by=20
removing the competition. Let {} mean "constructor with these arguments"
for non-aggregates. It will mean having to double-up on braces in some=20
cases to get to the initializer_list constructors, so you don't get=20
brace elision. But it does let you get at all the constructors you want.<br=
><br>If you're going to break the language, then break it in the way that l=
eads to the ideal solution. Don't break it and make the language more compl=
ex with :=3D and what not.<br><br></div><blockquote class=3D"gmail_quote" s=
tyle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-le=
ft: 1ex;"><div style=3D"margin-bottom:0cm"><span style=3D"font-style:normal=
"></span><span style=3D"font-style:normal">2.
Propose features to make brace-initialization more powerful, as to
fulfil its promise of uniform initialization.</span></div><div style=3D"mar=
gin-bottom:0cm"><span style=3D"font-style:normal"></span><br>
I consider (1) most
important, but let me end with some adventurous brain-storming about
(2). In my last post, I did briefly propose piggy-backing on a
hypothetical "named arguments" feature:</div><div style=3D"margin-bottom:0c=
m"><br>
vector <int> a
{size :=3D 42}; // OK: Pass size.</div><div style=3D"margin-bottom:0cm"><br=
>
I then allowed the
actual parameter name to be dropped:=20
</div><div style=3D"margin-bottom:0cm"><br>
vector <int> a
{:=3D 42}; // OK: Pass size.</div><div style=3D"margin-bottom:0cm"><br>
This then becomes
bare-bones syntax to indicate that an argument should be explicitly
matched against a parameter list. Since 42 is not an
initializer_list, this syntax enables the disambiguation in favour of
ordinary constructors, while keeping the possibility open for the
syntax to be extended in the future to support named arguments. Note
that this syntax is similar to yours, and will reap the full benefit
of brace-initialization (non-narrowing, etc.).</div></blockquote><div><br>J=
ust on quality of syntax issues, using :=3D here looks <i>horrible</i>.
It looks like you're trying to assign something. It's a syntax that=20
only really makes sense when dealing with named arguments. By taking out
the argument name, it now just looks really confusing and out of place. Ev=
en moreso if :=3D were adopted for named arguments, because then the user e=
xpects it to be used for named arguments<i></i>.<br><br></div><blockquote c=
lass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px=
#ccc solid;padding-left: 1ex;"><div style=3D"margin-bottom:0cm">
Now, let's go crazy and
allow the elision of the braces for the single-argument case:</div><div sty=
le=3D"margin-bottom:0cm"><br>
vector <int> a :=3D
42; // OK: Pass size.</div><div style=3D"margin-bottom:0cm"><br>
Voil=E0! We have derived
a new simple, intuitive and well-known syntax for new-style
non-narrowing initialization! This syntax is as intuitive and simple
as the old "=3D" syntax, and does not make dual use of the
assignment operator token "=3D", nor does it need the special
copy-initialization rules for the "=3D" syntax.</div></blockquote><div><br>=
You've
managed to make an ugly syntax even uglier by now implying that `:=3D`=20
means "initialize" in some cases, where in another it means "assign to=20
named argument" where in a third it means "call constructor".<br><br>The
user now has no idea what :=3D is supposed to even mean at this point.=20
Sometimes it gets wrapped in braces, sometimes it doesn't; sometimes a=20
name comes before it, sometimes it doesn't.<br><br>How is this less confusi=
ng than `{c: ...}`? At least that you can use everywhere in the same way:<b=
r><br><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 2=
50); border-color: rgb(187, 187, 187); border-style: solid; border-width: 1=
px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subpr=
ettyprint"><span style=3D"color: #000;" class=3D"styled-by-prettify">std</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify">vector</span><span st=
yle=3D"color: #080;" class=3D"styled-by-prettify"><int></span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> v</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify">c</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">:</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">...};</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"><br>std</span><span style=3D"color: #660;" class=3D"styled-by-prettify">:=
:</span><span style=3D"color: #000;" class=3D"styled-by-prettify">vector</s=
pan><span style=3D"color: #080;" class=3D"styled-by-prettify"><int></=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> v2 </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify">c</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">:</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">...};</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> </span><span style=3D"color: #800;" class=3D"styled-by-prettify">//Well, =
if it weren't explicit.</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"><br>std</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
">vector</span><span style=3D"color: #080;" class=3D"styled-by-prettify">&l=
t;int></span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #606;" class=3D"styled-by-prettify">Func</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">()</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #00=
8;" class=3D"styled-by-prettify">return</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify">c</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">:</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">...};</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #800;" =
class=3D"styled-by-prettify">//Again, if it weren't explicit.</span></div><=
/code></div><br>Whereas your syntax would look like this:<br><br><div class=
=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border-colo=
r: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wrap: b=
reak-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span=
style=3D"color: #000;" class=3D"styled-by-prettify">std</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">vector</span><span style=3D"color: #=
080;" class=3D"styled-by-prettify"><int></span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> v </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">:=3D</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">...;</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #800;" class=3D"styled-by-prettify">=
//But only if ... is one argument.</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>std</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify">vector</span><span style=3D"color: #080;" class=3D"styled-by-p=
rettify"><int></span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> v </span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">{:=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> <=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">...};</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #800;" class=3D"styled-by-prettify">//For multi-argument ...<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>std</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify">vector</span><span sty=
le=3D"color: #080;" class=3D"styled-by-prettify"><int></span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> v2 </span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color:=
#000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">{:=3D</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">...};</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-prettify"=
>//Why are there two =3D here?</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"><br>std</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify">vector</span><span style=3D"color: #080;" class=3D"styled-by-prett=
ify"><int></span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> </span><span style=3D"color: #606;" class=3D"styled-by-prettify">Fun=
c</span><span style=3D"color: #660;" class=3D"styled-by-prettify">()</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">return</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">{:=3D</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">...};</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>}</span></div></code></div><br>Oh,
and the whole "no need for copy-initialization" part? You may want to <a h=
ref=3D"http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2575.pdf">r=
ead this PDF</a>, as it is the reason the copy-list-initialization was adde=
d to
uniform initialization. Those reasons don't go away just because you=20
put a `:` before the equals.<br><br></div><blockquote class=3D"gmail_quote"=
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-=
left: 1ex;"><div style=3D"margin-bottom:0cm">
The syntax even works
well with initializer-lists:</div><div style=3D"margin-bottom:0cm"><br>
vector <int> a :=3D
{42}; // OK: Pass single element.</div><div style=3D"margin-bottom:0cm"><br=
>
This works fine because
it expands to an explicit argument match for an initializer_list:</div><div=
style=3D"margin-bottom:0cm"><br>
vector <int> a
{:=3D {42}}; // OK: Pass single element.</div><div style=3D"margin-bottom:0=
cm"><br>
> You can't
initialize aggregates with ()</div><div style=3D"margin-bottom:0cm"><br>
Perhaps this warrants
special consideration? Is there any reason why this should not be
allowed? E.g:</div><div style=3D"margin-bottom:0cm"><br>
struct Abc {int a, b,
c;};</div>
<div>Abc abc (1, 2, 3); </div></blockquote><blockquote class=3D"gmail_=
quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pa=
dding-left: 1ex;"><div style=3D"margin-bottom:0cm"><br>
Conceptually, the
language only needs to add an implicit constructor. This would solve
the emplace_back problem you demonstrated, I presume.</div></blockquote><di=
v><br>If it implicitly added a constructor, it would <i>no longer be an agg=
regate</i>. I would feel really uncomfortable about compilers automatically=
creating functions like that for simple classes.<br> </div><blockquot=
e class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: =
1px #ccc solid;padding-left: 1ex;"><div style=3D"margin-bottom:0cm">
> Honestly, I'm of
the opinion that, if we can't fix uniform initialization syntax to
actually be <i>uniform</i> and functionally replace all other
initialization <i>everywhere</i>, then we should just deprecate and
remove it ASAP.</div><div style=3D"margin-bottom:0cm"><br>
Well, beware of
throwing out the baby with the bathwater. Brace-initialization syntax
solves issues other than uniformity, such as narrowing and the
most-vexing-parse.<br></div><br></blockquote><div> </div><div>What goo=
d is having a solution that you can't reliably use? We can fix the most-vex=
ing-parse with an extra set of parenthesis when it comes up. And narrowing =
can be lived with.<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_942_30438184.1359241294344--
.
Author: vattilah-groups@yahoo.co.uk
Date: Sat, 26 Jan 2013 17:32:24 -0800 (PST)
Raw View
------=_Part_1142_13246314.1359250344997
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Note that I'm not here to shoot your proposal down. I think your proposal=
=20
has merit, and I wish you well in its progress, if not in the current form.
=20
> Giving the user the ability to resolve the ambiguity themselves should=20
not be contingent on making the ambiguity illegal. The former is the most=
=20
important thing, because that is what allows the user to actually solve the=
=20
problem.
=20
The language already has ample features to deal with ambiguity, as long as=
=20
you are willing to use them, i.e. not restrict yourself to=20
brace-initialization. So users can survive until an ideal solution for=20
brace-initialization is found. Also, as many have argued, improvements in=
=20
the library can be made to resolve mentioned ambiguities in std::vector,=20
even with the consistent use of brace-initialization. I don't argue that=20
any of these options are preferable to your solution, but they are=20
undeniable available. By dismissing them, you are overstating your case.
=20
> Lastly, if they *are* willing to make a breaking change, I would much=20
prefer they prevent the ambiguity directly by removing the competition. Let=
=20
{} mean "constructor with these arguments" for non-aggregates.=20
=20
There are different types of breaking changes. A silent break, as the one=
=20
you are suggesting here, is considered the worst kind by most. Hence I very=
=20
much disagree with you here. This rule change would silently change vector=
=20
<int> {20} to mean a vector of 20 default-constructed elements, not a=20
vector of one element (20) as currently is the case. The bug this causes in=
=20
client code may not even show up in testing.
=20
> [Your horribly ugly syntax] means "initialize" in some cases, where in=20
another it means "assign to named argument" where in a third it means "call=
=20
constructor".
=20
Argument binding is initialization, and initialization implies constructor=
=20
calls, so I don't get your point here, other than that you obviously didn't=
=20
particularly like going down this path. :-)
=20
> How is [your syntax {:=3D ...}] less confusing than `{c: ...}`?
=20
I didn't claim that. I deem them at the same confusion level. My syntax=20
suggestion is just an exploration of the design space in the direction of=
=20
named arguments. I think that has some attractive features, but it is just=
=20
brain-storming at this point. But you don't seem particularly keen to=20
explore this path, so I will disengage.=20
=20
> Oh, and the whole "no need for copy-initialization" part? You may want to=
=20
read this PDF, as it is the reason the copy-list-initialization was added=
=20
to uniform initialization. Those reasons don't go away just because you put=
=20
a `:` before the equals.
=20
I think you are complicating things here. I showed how my suggested=20
brace-less syntax is a simple syntactic transformation from=20
direct-initialization using braces ("constructing by calling a=20
constructor", as the article you linked calls it). The elision of the=20
braces is not meant to change semantics. If you think it should, that is=20
another matter. Note that the linked article explores the adaptation of=20
initializer-list in a "=3D" context, where it needs to fit with the existin=
g=20
rules.
=20
> If [C++] implicitly added a constructor [to aggregates], it would no=20
longer be an aggregate.
=20
This does not have to be the rule. An aggregate already has an implicit=20
default constructor, copy constructor and assignment operator.
=20
Note the formal definition from the C++ standard (C++03 8.5.1 =A71): An=20
aggregate is an array or a class (clause 9) with no *user-declared*construc=
tors (12.1), no private or protected non-static data members=20
(clause 11), no base classes (clause 10), and no virtual functions (10.3).
=20
> What good is having a solution that you can't reliably use?
=20
Well, perfection is the enemy of progress. I think it is often a good=20
approach to do things piecemeal. Often the first step is something everyone=
=20
can agree on, while further steps are more difficult, or too early in their=
=20
exploration, to find consensus.
=20
Regards,
Vidar Hasfjord
=20
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To post to this group, send email to std-proposals@isocpp.org.
To unsubscribe from this group, send email to std-proposals+unsubscribe@iso=
cpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/?hl=3Den.
------=_Part_1142_13246314.1359250344997
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div style=3D"margin-bottom: 0cm;" class=3D"western">Note that I'm not here
to shoot your proposal down. I think your proposal has merit, and I
wish you well in its progress, if not in the current form.</div><div style=
=3D"margin-bottom: 0cm;" class=3D"western"> </div><div style=3D"margin=
-bottom: 0cm;" class=3D"western">> Giving the user
the ability to resolve the ambiguity themselves should not be
contingent on making the ambiguity illegal. The former is the most
important thing, because that is what allows the user to actually
solve the problem.</div><div style=3D"margin-bottom: 0cm;" class=3D"western=
"> </div><div style=3D"margin-bottom: 0cm;" class=3D"western">The lang=
uage already
has ample features to deal with ambiguity, as long as you are
willing to use them, i.e. not restrict yourself to
brace-initialization. So users can survive until an ideal solution
for brace-initialization is found. Also, as many have argued,
improvements in the library can be made to resolve mentioned
ambiguities in std::vector, even with the consistent use of
brace-initialization. I don't argue that any of these options are
preferable to your solution, but they are undeniable available. By
dismissing them, you are overstating your case.</div><div style=3D"margin-b=
ottom: 0cm;" class=3D"western"> </div><div style=3D"margin-bottom: 0cm=
;" class=3D"western">> Lastly, if they
<i>are</i> willing to make a breaking change, I would much prefer
they prevent the ambiguity directly by removing the competition. Let
{} mean "constructor with these arguments" for
non-aggregates.=20
</div><div style=3D"margin-bottom: 0cm;" class=3D"western"> </div><div=
style=3D"margin-bottom: 0cm;" class=3D"western">There are different
types of breaking changes. A silent break, as the one you are
suggesting here, is considered the worst kind by most. Hence I very
much disagree with you here. This rule change would silently change
vector <int> {20} to mean a vector of 20 default-constructed
elements, not a vector of one element (20) as currently is the case.
The bug this causes in client code may not even show up in testing.</div><d=
iv style=3D"margin-bottom: 0cm;" class=3D"western"> </div><div style=
=3D"margin-bottom: 0cm;" class=3D"western">> [Your horribly
ugly syntax] means "initialize" in some cases, where in
another it means "assign to named argument" where in a
third it means "call constructor".</div><div style=3D"margin-bottom: 0cm;" =
class=3D"western"> </div><div style=3D"margin-bottom: 0cm;" class=3D"w=
estern">Argument binding is
initialization, and initialization implies constructor calls, so I
don't get your point here, other than that you obviously didn't
particularly like going down this path. :-)</div><div style=3D"margin-botto=
m: 0cm;" class=3D"western"> </div><div style=3D"margin-bottom: 0cm;" c=
lass=3D"western">> How is [your
syntax {:=3D ...}] less confusing than `{c: ...}`?</div><div style=3D"margi=
n-bottom: 0cm;" class=3D"western"> </div><div style=3D"margin-bottom: =
0cm;" class=3D"western">I didn't claim that. I
deem them at the same confusion level. My syntax suggestion is just
an exploration of the design space in the direction of named
arguments. I think that has some attractive features, but it is just
brain-storming at this point. But you don't seem particularly keen to
explore this path, so I will disengage.=20
</div><div style=3D"margin-bottom: 0cm;" class=3D"western"> </div><div=
style=3D"margin-bottom: 0cm;" class=3D"western">> Oh, and the whole
"no need for copy-initialization" part? You may want to
read this PDF, as it is the reason the copy-list-initialization was
added to uniform initialization. Those reasons don't go away just
because you put a `:` before the equals.</div><div style=3D"margin-bottom: =
0cm;" class=3D"western"> </div><div style=3D"margin-bottom: 0cm;" clas=
s=3D"western">I think you are
complicating things here. I showed how my suggested brace-less syntax
is a simple syntactic transformation from direct-initialization using
braces ("constructing by calling a constructor", as the
article you linked calls it). The elision of the braces is not meant
to change semantics. If you think it should, that is another matter.
Note that the linked article explores the adaptation of
initializer-list in a "=3D" context, where it needs to fit
with the existing rules.</div><div style=3D"margin-bottom: 0cm;" class=3D"w=
estern"> </div><div style=3D"margin-bottom: 0cm;" class=3D"western">&g=
t; If [C++]
implicitly added a constructor [to aggregates], it would no longer be
an aggregate.</div><div style=3D"margin-bottom: 0cm;" class=3D"western">&nb=
sp;</div><div style=3D"margin-bottom: 0cm;" class=3D"western">This does not=
have to
be the rule. An aggregate already has an implicit default
constructor, copy constructor and assignment operator.</div><div style=3D"m=
argin-bottom: 0cm;" class=3D"western"> </div><div style=3D"margin-bott=
om: 0cm;" class=3D"western">Note the formal
definition from the C++ standard (C++03 8.5.1 =A71): An aggregate is
an array or a class (clause 9) with no <b>user-declared</b>
constructors (12.1), no private or protected non-static data members
(clause 11), no base classes (clause 10), and no virtual functions
(10.3).</div><div style=3D"margin-bottom: 0cm;" class=3D"western"> </d=
iv><div style=3D"margin-bottom: 0cm;" class=3D"western">> What good is
having a solution that you can't reliably use?</div><div style=3D"margin-bo=
ttom: 0cm;" class=3D"western"> </div><div style=3D"margin-bottom: 0cm;=
" class=3D"western">Well, perfection is the
enemy of progress. I think it is often a good approach to do things
piecemeal. Often the first step is something everyone can agree on,
while further steps are more difficult, or too early in their
exploration, to find consensus.</div><div style=3D"margin-bottom: 0cm;" cla=
ss=3D"western"> </div><div style=3D"margin-bottom: 0cm;" class=3D"west=
ern">Regards,</div><div style=3D"margin-bottom: 0cm;" class=3D"western">Vid=
ar Hasfjord</div><div style=3D"margin-bottom: 0cm;" class=3D"western"> =
;</div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
To unsubscribe from this group, send email to std-proposals+unsubscribe@iso=
cpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_1142_13246314.1359250344997--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sat, 26 Jan 2013 18:51:16 -0800 (PST)
Raw View
------=_Part_1084_3025184.1359255076462
Content-Type: text/plain; charset=ISO-8859-1
On Saturday, January 26, 2013 5:32:24 PM UTC-8, vattila...@yahoo.co.uk
wrote:
>
> Note that I'm not here to shoot your proposal down. I think your proposal
> has merit, and I wish you well in its progress, if not in the current form.
>
> > Giving the user the ability to resolve the ambiguity themselves should
> not be contingent on making the ambiguity illegal. The former is the most
> important thing, because that is what allows the user to actually solve the
> problem.
>
> The language already has ample features to deal with ambiguity, as long as
> you are willing to use them, i.e. not restrict yourself to
> brace-initialization. So users can survive until an ideal solution for
> brace-initialization is found.
>
Having a broken feature is bad. It's worse than not having the feature at
all. Especially when you've got Bjarne Stroustrup using it *everywhere* in
his book like it's not broken; that's *thousands* of naive C++ programmers
that are going to get hit with the problem.
> Also, as many have argued, improvements in the library can be made to
> resolve mentioned ambiguities in std::vector, even with the consistent use
> of brace-initialization. I don't argue that any of these options are
> preferable to your solution, but they are undeniable available.
>
Available, but they *don't fix the problem*. They fix the problem for
std::vector. But they don't fix the problem for <insert some type here>.
It's a problem introduced by a language feature; that's the level where it
needs to be fixed.
The longer this problem is present, the worse it will get. The more people
are going to encounter it, and the more people are going to have
problems/malformed code. Eventually, what's going to happen is that people
will idiomatically *avoid* uniform initialization syntax, deeming it worse
than regular initialization. That's what the C++ idioms are going to be in
5 years if something isn't done to correct the problem at the language
level.
If I can't write `T {20, 30}` in some template code and have some idea of
what it will actually do, then there is a problem. My library level solution<https://groups.google.com/a/isocpp.org/d/topic/std-proposals/m9KFTXtHJGY/discussion>can't fix that; only a language-level solution can.
> What good is having a solution that you can't reliably use?
>
> Well, perfection is the enemy of progress. I think it is often a good
> approach to do things piecemeal. Often the first step is something everyone
> can agree on, while further steps are more difficult, or too early in their
> exploration, to find consensus.
>
We currently cannot reliably use uniform initialization syntax everywhere
because of these issues. What you propose... would *continue* to prevent us
from reliably using uniform initialization syntax everywhere. Code that
does it is no more safe; it just emits a compiler error. Sometimes. That's
not progress; that's a lateral move.
Furthermore, by not allowing this "progress", we force the committee to
provide a real solution ASAP. This is a legitimate problem that must be
addressed. But by removing the simple "solution", we force them to look at
real solutions that make uniform initialization actually work.
The last thing we want is for the committee to just ban the ambiguity, thus
making the problem not sufficiently urgent. Without pressure to get a real
fix, people can spend 10 years arguing over different approaches to no
avail.
Just look at this thread. You've got people trying to piggyback named
parameters and initialization forwarding and other things into this
discussion. As though these *entirely orthogonal issues* had anything to do
with fixing this *specific* problem. Everyone is going to try to stick
their own spin on it, with their own specific issues and ideas about it.
People who think that uniform initialization is itself completely
wrongheaded will try to shoot it down or otherwise sabotage it. People who
want named parameters will make the fix contingent on them. And so forth.
Everyone's little pet issues will come out, and they'll try to shoehorn the
uniform initialization fix into them.
This kind of discussion goes nowhere fast. My solution is designed to
affect as little else as possible. It collides with nothing else, and it
isn't related to any other issues. It's a tight, focused fix for a real
deficiency in the language feature. You could argue that some of the
constructs are superfluous, but as far as I'm concerned, as long as we get
c: and l: into the spec, the problem is fixed.
Give the committee time, and they will squander it. And your suggestion
gives them time. Which is exactly what you want: to make minimal progress
now, then find the perfect solution later.
It is your quest for the perfect overall solution that is the enemy of
progress towards *any* overall solution. I don't claim that my solution is
perfect. But it is unquestionably a *complete solution*, resolving the
ambiguity entirely.
This idea may sound political, but it is an effective way to force action.
Prevent people from doing the minimum work needed to get by, and you force
them to provide an actual working solution faster.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To post to this group, send email to std-proposals@isocpp.org.
To unsubscribe from this group, send email to std-proposals+unsubscribe@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_1084_3025184.1359255076462
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Saturday, January 26, 2013 5:32:24 PM UTC-8, vattila...@yahoo.co.uk wrot=
e:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;">
<div style=3D"margin-bottom:0cm">Note that I'm not here
to shoot your proposal down. I think your proposal has merit, and I
wish you well in its progress, if not in the current form.</div><div style=
=3D"margin-bottom:0cm"> </div><div style=3D"margin-bottom:0cm">> Gi=
ving the user
the ability to resolve the ambiguity themselves should not be
contingent on making the ambiguity illegal. The former is the most
important thing, because that is what allows the user to actually
solve the problem.</div><div style=3D"margin-bottom:0cm"> </div><div s=
tyle=3D"margin-bottom:0cm">The language already
has ample features to deal with ambiguity, as long as you are
willing to use them, i.e. not restrict yourself to
brace-initialization. So users can survive until an ideal solution
for brace-initialization is found.</div></blockquote><div><br>Having a brok=
en feature is bad. It's worse than not having the feature at all. Especiall=
y when you've got Bjarne Stroustrup using it <i>everywhere</i> in his book =
like it's not broken; that's <i>thousands</i> of naive C++ programmers that=
are going to get hit with the problem.<br> </div><blockquote class=3D=
"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc s=
olid;padding-left: 1ex;"><div style=3D"margin-bottom:0cm">Also, as many hav=
e argued,
improvements in the library can be made to resolve mentioned
ambiguities in std::vector, even with the consistent use of
brace-initialization. I don't argue that any of these options are
preferable to your solution, but they are undeniable available.</div></bloc=
kquote><div><br>Available, but they <i>don't fix the problem</i>. They fix =
the problem for std::vector. But they don't fix the problem for <insert =
some type here>. It's a problem introduced by a language feature; that's=
the level where it needs to be fixed.<br><br>The longer this problem is pr=
esent, the worse it will get. The more people are going to encounter it, an=
d the more people are going to have problems/malformed code. Eventually, wh=
at's going to happen is that people will idiomatically <i>avoid</i> uniform=
initialization syntax, deeming it worse than regular initialization. That'=
s what the C++ idioms are going to be in 5 years if something isn't done to=
correct the problem at the language level.<br><br>If I can't write `T {20,=
30}` in some template code and have some idea of what it will actually do,=
then there is a problem. <a href=3D"https://groups.google.com/a/isocpp.org=
/d/topic/std-proposals/m9KFTXtHJGY/discussion">My library level solution</a=
> can't fix that; only a language-level solution can.<br><br></div><blockqu=
ote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left=
: 1px #ccc solid;padding-left: 1ex;"><div style=3D"margin-bottom:0cm"></div=
><div style=3D"margin-bottom:0cm">> What good is
having a solution that you can't reliably use?</div><div style=3D"margin-bo=
ttom:0cm"> </div><div style=3D"margin-bottom:0cm">Well, perfection is =
the
enemy of progress. I think it is often a good approach to do things
piecemeal. Often the first step is something everyone can agree on,
while further steps are more difficult, or too early in their
exploration, to find consensus.</div></blockquote><div><br>We currently can=
not reliably use uniform initialization syntax everywhere because of these =
issues. What you propose... would <i>continue</i> to prevent us from reliab=
ly using uniform initialization syntax everywhere. Code that does it is no =
more safe; it just emits a compiler error. Sometimes. That's not progress; =
that's a lateral move.<br><br>Furthermore, by not allowing this "progress",=
we force the committee to provide a real solution ASAP. This is a legitima=
te problem that must be addressed. But by removing the simple "solution", w=
e force them to look at real solutions that make uniform initialization act=
ually work.<br><br>The last thing we want is for the committee to just ban =
the ambiguity, thus making the problem not sufficiently urgent. Without pre=
ssure to get a real fix, people can spend 10 years arguing over different a=
pproaches to no avail.<br><br>Just look at this thread. You've got people t=
rying to piggyback named parameters and initialization forwarding and other=
things into this discussion. As though these <i>entirely orthogonal issues=
</i> had anything to do with fixing this <i>specific</i> problem. Everyone =
is going to try to stick their own spin on it, with their own specific issu=
es and ideas about it. People who think that uniform initialization is itse=
lf completely wrongheaded will try to shoot it down or otherwise sabotage i=
t. People who want named parameters will make the fix contingent on them. A=
nd so forth. Everyone's little pet issues will come out, and they'll try to=
shoehorn the uniform initialization fix into them.<br><br>This kind of dis=
cussion goes nowhere fast. My solution is designed to affect as little else=
as possible. It collides with nothing else, and it isn't related to any ot=
her issues. It's a tight, focused fix for a real deficiency in the language=
feature. You could argue that some of the constructs are superfluous, but =
as far as I'm concerned, as long as we get c: and l: into the spec, the pro=
blem is fixed.<br><br>Give the committee time, and they will squander it. A=
nd your suggestion gives them time. Which is exactly what you want: to make=
minimal progress now, then find the perfect solution later.<br><br>It is y=
our quest for the perfect overall solution that is the enemy of progress to=
wards <i>any</i> overall solution. I don't claim that my solution is perfec=
t. But it is unquestionably a <i>complete solution</i>, resolving the ambig=
uity entirely.<br><br>This idea may sound political, but it is an effective=
way to force action. Prevent people from doing the minimum work needed to =
get by, and you force them to provide an actual working solution faster.<br=
></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
To unsubscribe from this group, send email to std-proposals+unsubscribe@iso=
cpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_1084_3025184.1359255076462--
.
Author: vattilah-groups@yahoo.co.uk
Date: Sat, 26 Jan 2013 21:52:14 -0800 (PST)
Raw View
------=_Part_1182_32589725.1359265934749
Content-Type: text/plain; charset=ISO-8859-1
Hi Nicol,
I get all your arguments for improving uniform initialization so that
overload resolution can select ordinary constructors before
il-constructors. Consider me convinced.
What I didn't get is why you are downplaying the importance of fixing the
language so that it ensures that existing code, that already suffers the
very problems you so poignantly highlight in the motivating part of your
proposal, no longer compiles with silent bugs.
> The last thing we want is for the committee to just ban the ambiguity,
thus making the problem not sufficiently urgent. Without pressure to get a
real fix, people can spend 10 years arguing over different approaches to no
avail.
OK. Now I understand where you are coming from on this. Yes, by all
accounts, it can take an awful lot of time and effort to get things through
the standardisation process. That said, I think this is unavoidable for any
extensive proposal like yours. And some design space exploration and
scrutiny may actually be good.
Regarding revoking the il-preference rule, our main difference of opinion,
consider this scenario:
After successful promotion your proposal is accepted. If it doesn't catch
the bus for C++14, which in all probability is unlikely for such an
extensive feature, then you are looking at C++17. That's 4 to 5 years away.
In the meantime code is written for C++11 and C++14. Since nothing is done
to prevent silent bugs caused by this issue, broken code will prevail, and
novices will be stumped. Further more, only code that is rewritten using
C++17 with this issue in mind, may fix the bugs. Legacy code may persist
for ever with such silent bugs, even if compiled with the latest C++17
compilers.
I argue that we should seek to eliminate those silent bugs. If at all
possible, try to achieve that in C++14. Then move on to improve uniform
initialization further.
Regards,
Vidar Hasfjord
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To post to this group, send email to std-proposals@isocpp.org.
To unsubscribe from this group, send email to std-proposals+unsubscribe@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_1182_32589725.1359265934749
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div style=3D"margin-bottom: 0cm;" class=3D"western">Hi Nicol,</div><div st=
yle=3D"margin-bottom: 0cm;" class=3D"western"> </div><div style=3D"mar=
gin-bottom: 0cm;" class=3D"western">I get all your
arguments for improving uniform initialization so that overload
resolution can select ordinary constructors before il-constructors.
Consider me convinced.</div><div style=3D"margin-bottom: 0cm;" class=3D"wes=
tern"> </div><div style=3D"margin-bottom: 0cm;" class=3D"western">What=
I didn't get is
why you are downplaying the importance of fixing the language so that
it ensures that existing code, that already suffers the very problems
you so poignantly highlight in the motivating part of your proposal,
no longer compiles with silent bugs.</div><div style=3D"margin-bottom: 0cm;=
" class=3D"western"> </div><div style=3D"margin-bottom: 0cm;" class=3D=
"western">> The last thing we
want is for the committee to just ban the ambiguity, thus making the
problem not sufficiently urgent. Without pressure to get a real fix,
people can spend 10 years arguing over different approaches to no
avail.</div><div style=3D"margin-bottom: 0cm;" class=3D"western"> </di=
v><div style=3D"margin-bottom: 0cm;" class=3D"western">OK. Now I understand
where you are coming from on this. Yes, by all accounts, it can take
an awful lot of time and effort to get things through the
standardisation process. That said, I think this is unavoidable for
any extensive proposal like yours. And some <span style=3D"font-style: norm=
al;">design
space exploration and scrutiny </span>may actually be good.</div><div style=
=3D"margin-bottom: 0cm;" class=3D"western"> </div><div style=3D"margin=
-bottom: 0cm;" class=3D"western">Regarding revoking the
il-preference rule, our main difference of opinion, consider this
scenario:</div><div style=3D"margin-bottom: 0cm;" class=3D"western"> <=
/div><div style=3D"margin-bottom: 0cm;" class=3D"western">After successful
promotion your proposal is accepted. If it doesn't catch the bus for
C++14, which in all probability is unlikely for such an extensive
feature, then you are looking at C++17. That's 4 to 5 years away. In
the meantime code is written for C++11 and C++14. Since nothing is
done to prevent silent bugs caused by this issue, broken code will
prevail, and novices will be stumped. Further more, only code that is rewri=
tten using C++17 with
this issue in mind, may fix the bugs. Legacy code may persist for
ever with such silent bugs, even if compiled with the latest C++17
compilers.</div><div style=3D"margin-bottom: 0cm;" class=3D"western"> =
</div><div style=3D"margin-bottom: 0cm;" class=3D"western">I argue that we =
should
seek to eliminate those silent bugs. If at all possible, try to
achieve that in C++14. Then move on to improve uniform initialization
further.</div><div style=3D"margin-bottom: 0cm;" class=3D"western"> </=
div><div style=3D"margin-bottom: 0cm;" class=3D"western">Regards,</div><div=
style=3D"margin-bottom: 0cm;" class=3D"western">Vidar Hasfjord</div><div s=
tyle=3D"margin-bottom: 0cm;" class=3D"western"> </div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
To unsubscribe from this group, send email to std-proposals+unsubscribe@iso=
cpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_1182_32589725.1359265934749--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sun, 27 Jan 2013 14:52:35 -0800 (PST)
Raw View
------=_Part_260_30729042.1359327155959
Content-Type: text/plain; charset=ISO-8859-1
On Saturday, January 26, 2013 9:52:14 PM UTC-8, vattila...@yahoo.co.uk
wrote:
>
> Hi Nicol,
>
> I get all your arguments for improving uniform initialization so that
> overload resolution can select ordinary constructors before
> il-constructors. Consider me convinced.
>
> What I didn't get is why you are downplaying the importance of fixing the
> language so that it ensures that existing code, that already suffers the
> very problems you so poignantly highlight in the motivating part of your
> proposal, no longer compiles with silent bugs.
>
> > The last thing we want is for the committee to just ban the ambiguity,
> thus making the problem not sufficiently urgent. Without pressure to get a
> real fix, people can spend 10 years arguing over different approaches to no
> avail.
>
> OK. Now I understand where you are coming from on this. Yes, by all
> accounts, it can take an awful lot of time and effort to get things through
> the standardisation process. That said, I think this is unavoidable for any
> extensive proposal like yours.
>
That's part of my point: this is *not* an "extensive proposal". It breaks
no existing code. The changes, in terms of volume of specification
language, are minimal. It doesn't (to my knowledge) have any problems with
the parser. It is short, simple, and focused, with no dependencies or other
complications.
It's less disruptive and extensive than polymorphic lambdas to the
language, and causes no breaking changes unlike the proposed changes to
lambda capturing of `this`. Yet both of those are on deck for C++14. Why?
Because we recognize that these are serious problems that must be corrected
ASAP.
And some design space exploration and scrutiny may actually be good.
>
Considering the discussion here, which has tried to conflate solving this
problem with a host of irrelevant personal issues (forwarding
initializations, non-uniform initialization, your own suggestion to use
non-existent named parameter syntax, etc), I don't see any of that as being
"good". The last thing we want is for people to piggy-back their completely
separate ideas onto this essential language feature.
This is no different from legislatures attaching "riders" to important
bills which have nothing to do with the actual law in question, because
they wouldn't be able to get them passed otherwise.
I don't see anything coming out of "exploring the design space" other than
everyone trying to justify their own little pet features by fixing uniform
initialization. I would much rather we fix uniform initialization by fixing
uniform initialization and *only* that.
Regarding revoking the il-preference rule, our main difference of opinion,
> consider this scenario:
>
> After successful promotion your proposal is accepted. If it doesn't catch
> the bus for C++14, which in all probability is unlikely for such an
> extensive feature, then you are looking at C++17. That's 4 to 5 years away.
> In the meantime code is written for C++11 and C++14. Since nothing is done
> to prevent silent bugs caused by this issue, broken code will prevail, and
> novices will be stumped. Further more, only code that is rewritten using
> C++17 with this issue in mind, may fix the bugs. Legacy code may persist
> for ever with such silent bugs, even if compiled with the latest C++17
> compilers.
>
> I argue that we should seek to eliminate those silent bugs. If at all
> possible, try to achieve that in C++14. Then move on to improve uniform
> initialization further.
>
I believe that eliminating those silent bugs should be done by improving
uniform initialization. By C++14.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_260_30729042.1359327155959
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Saturday, January 26, 2013 9:52:14 PM UTC-8, vattila...@yahoo.co=
..uk wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:=
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<div style=3D"margin-bottom:0cm">Hi Nicol,</div><div style=3D"margin-bottom=
:0cm"> </div><div style=3D"margin-bottom:0cm">I get all your
arguments for improving uniform initialization so that overload
resolution can select ordinary constructors before il-constructors.
Consider me convinced.</div><div style=3D"margin-bottom:0cm"> </div><d=
iv style=3D"margin-bottom:0cm">What I didn't get is
why you are downplaying the importance of fixing the language so that
it ensures that existing code, that already suffers the very problems
you so poignantly highlight in the motivating part of your proposal,
no longer compiles with silent bugs.</div><div style=3D"margin-bottom:0cm">=
</div><div style=3D"margin-bottom:0cm">> The last thing we
want is for the committee to just ban the ambiguity, thus making the
problem not sufficiently urgent. Without pressure to get a real fix,
people can spend 10 years arguing over different approaches to no
avail.</div><div style=3D"margin-bottom:0cm"> </div><div style=3D"marg=
in-bottom:0cm">OK. Now I understand
where you are coming from on this. Yes, by all accounts, it can take
an awful lot of time and effort to get things through the
standardisation process. That said, I think this is unavoidable for
any extensive proposal like yours.</div></blockquote><div><br>That's part o=
f my point: this is <i>not</i> an "extensive proposal". It breaks no existi=
ng code. The changes, in terms of volume of specification language, are min=
imal. It doesn't (to my knowledge) have any problems with the parser. It is=
short, simple, and focused, with no dependencies or other complications.<b=
r><br>It's less disruptive and extensive than polymorphic lambdas to the la=
nguage, and causes no breaking changes unlike the proposed changes to lambd=
a capturing of `this`. Yet both of those are on deck for C++14. Why? Becaus=
e we recognize that these are serious problems that must be corrected ASAP.=
<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-l=
eft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div style=3D"ma=
rgin-bottom:0cm"> And some <span style=3D"font-style:normal">design
space exploration and scrutiny </span>may actually be good.</div></blockquo=
te><div><br>Considering the discussion here, which has tried to conflate so=
lving this problem with a host of irrelevant personal issues (forwarding in=
itializations, non-uniform initialization, your own suggestion to use non-e=
xistent named parameter syntax, etc), I don't see any of that as being "goo=
d". The last thing we want is for people to piggy-back their completely sep=
arate ideas onto this essential language feature.<br><br>This is no differe=
nt from legislatures attaching "riders" to important bills which have nothi=
ng to do with the actual law in question, because they wouldn't be able to =
get them passed otherwise.<br><br>I don't see anything coming out of "explo=
ring the design space" other than everyone trying to justify their own litt=
le pet features by fixing uniform initialization. I would much rather we fi=
x uniform initialization by fixing uniform initialization and <i>only</i> t=
hat.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;marg=
in-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div style=
=3D"margin-bottom:0cm"></div><div style=3D"margin-bottom:0cm">Regarding rev=
oking the
il-preference rule, our main difference of opinion, consider this
scenario:</div><div style=3D"margin-bottom:0cm"> </div><div style=3D"m=
argin-bottom:0cm">After successful
promotion your proposal is accepted. If it doesn't catch the bus for
C++14, which in all probability is unlikely for such an extensive
feature, then you are looking at C++17. That's 4 to 5 years away. In
the meantime code is written for C++11 and C++14. Since nothing is
done to prevent silent bugs caused by this issue, broken code will
prevail, and novices will be stumped. Further more, only code that is rewri=
tten using C++17 with
this issue in mind, may fix the bugs. Legacy code may persist for
ever with such silent bugs, even if compiled with the latest C++17
compilers.</div></blockquote><blockquote class=3D"gmail_quote" style=3D"mar=
gin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><=
div style=3D"margin-bottom:0cm"> </div><div style=3D"margin-bottom:0cm=
">I argue that we should
seek to eliminate those silent bugs. If at all possible, try to
achieve that in C++14. Then move on to improve uniform initialization
further.</div></blockquote><div><br>I believe that eliminating those silent=
bugs should be done by improving uniform initialization. By C++14.<br></di=
v>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_260_30729042.1359327155959--
.
Author: vattilah-groups@yahoo.co.uk
Date: Sun, 27 Jan 2013 20:26:50 -0800 (PST)
Raw View
------=_Part_1032_17699616.1359347210787
Content-Type: text/plain; charset=ISO-8859-1
On Saturday, 26 January 2013 08:54:51 UTC, Nikolay Ivchenkov wrote:
>
> On Saturday, January 26, 2013 3:11:15 AM UTC+4, vattila...@yahoo.co.ukwrote:
>>
>>
>> Existing ways to disambiguate:
>>
>> vector <int> a (42); // OK: Pass size.
>> vector <int> a ({42}); // OK: Pass single element.
>>
>
> For the latter initialization there are two viable constructors:
>
> explicit vector(size_type n);
> vector(initializer_list<T>, const Allocator& = Allocator());
>
Sorry, you're right. I didn't read your post properly the first time
around. So, in the case the il-preference rule was revoked, then vector
<int> ({42}) would not be sufficient to disambiguate in favour of the
il-constructor. But you could do
vector <int> a = {42}; // OK: Pass single element (copy-initialization
excludes explict constructors).
or
vector <int> a (initializer_list <int> {42}); // OK: Pass single element.
Which is a mouthful, but at least it is very explicit, alerting the
programmer to the resolution of ambiguity here.
Regards,
Vidar Hasfjord
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To post to this group, send email to std-proposals@isocpp.org.
To unsubscribe from this group, send email to std-proposals+unsubscribe@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_1032_17699616.1359347210787
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Saturday, 26 January 2013 08:54:51 UTC, Nikolay Ivchenkov wrote:<blockq=
uote style=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-col=
or: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid;" =
class=3D"gmail_quote">On Saturday, January 26, 2013 3:11:15 AM UTC+4, <a>va=
ttila...@yahoo.co.uk</a> wrote:<blockquote style=3D"margin: 0px 0px 0px 0.8=
ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-w=
idth: 1px; border-left-style: solid;" class=3D"gmail_quote"><div style=3D"m=
argin-bottom: 0cm;"><br>
Existing ways to
disambiguate:</div><div style=3D"margin-bottom: 0cm;"><br>
vector <int> a
(42); // OK: Pass size.</div>
<div style=3D"margin-bottom: 0cm;">vector <int> a
({42}); // OK: Pass single element.</div></blockquote><div><br>For the latt=
er initialization there are two viable constructors:<br><br> &nb=
sp; explicit vector(size_type n);<br> vector(initializer_=
list<T>, const Allocator& =3D Allocator());</div></blockquote><di=
v> </div><div>Sorry, you're right. I didn't read your post properly th=
e first time around. So, in the case the il-preference rule was revoke=
d, then vector <int> ({42}) would not be sufficient to disa=
mbiguate in favour of the il-constructor. But you could do</div><div> =
</div><div>vector <int> a =3D {42}; // OK: Pass single element (copy-=
initialization excludes explict constructors).</div><div> </div><div>o=
r</div><div> </div><div>vector <int> a (initializer_list <int=
> {42}); // OK: Pass single element.</div><div> </div><div>Which is=
a mouthful, but at least it is very explicit, alerting the programmer to t=
he resolution of ambiguity here.</div><div> </div><div>Regards,</div><=
div>Vidar Hasfjord</div><div> </div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
To unsubscribe from this group, send email to std-proposals+unsubscribe@iso=
cpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_1032_17699616.1359347210787--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Mon, 28 Jan 2013 04:19:30 -0800 (PST)
Raw View
------=_Part_563_9673106.1359375571043
Content-Type: text/plain; charset=ISO-8859-1
On Saturday, January 26, 2013 11:53:48 PM UTC+4, vattila...@yahoo.co.uk
wrote:
>
>
> > You can't initialize aggregates with ()
>
> Perhaps this warrants special consideration? Is there any reason why this
> should not be allowed? E.g:
>
> struct Abc {int a, b, c;};
> Abc abc (1, 2, 3);
>
> Conceptually, the language only needs to add an implicit constructor. This
> would solve the emplace_back problem you demonstrated, I presume.
>
I think that aggregate initialization and initialization by an
initializer-list constructor should look similar, because they are supposed
to perform an itemwise initialization, while initialization with () is
commonly used for an arbitrary initialization. This is one of the reasons
why I don't like suggested {c:} and {l:}.
On Monday, January 28, 2013 8:26:50 AM UTC+4, vattila...@yahoo.co.uk wrote:
>
> So, in the case the il-preference rule was revoked, then vector <int>
> ({42}) would not be sufficient to disambiguate in favour of the
> il-constructor. But you could do
>
> vector <int> a = {42}; // OK: Pass single element (copy-initialization
> excludes explict constructors).
>
1) Explicit constructors are still considered here.
2) In the following case
vector <int> a = {42, 1};
there are two viable converting constructors.
3) There are constructs (such as new-expressions and mem-initializers)
where only direct-initialization is available.
or
>
> vector <int> a (initializer_list <int> {42}); // OK: Pass single element.
>
> Which is a mouthful
>
while list-initializaiton is supposed to be terse :-)
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To post to this group, send email to std-proposals@isocpp.org.
To unsubscribe from this group, send email to std-proposals+unsubscribe@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_563_9673106.1359375571043
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Saturday, January 26, 2013 11:53:48 PM UTC+4, vattila...@yahoo.co.uk wro=
te:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;"><br><div style=3D"margin-bo=
ttom:0cm">
> You can't
initialize aggregates with ()</div><div style=3D"margin-bottom:0cm"><br>
Perhaps this warrants
special consideration? Is there any reason why this should not be
allowed? E.g:</div><div style=3D"margin-bottom:0cm"><br>
struct Abc {int a, b,
c;};</div>
<div style=3D"margin-bottom:0cm">Abc abc (1, 2, 3);</div><div style=3D"marg=
in-bottom:0cm"><br>
Conceptually, the
language only needs to add an implicit constructor. This would solve
the emplace_back problem you demonstrated, I presume.</div></blockquote><di=
v><br>I
think that aggregate initialization and initialization by an=20
initializer-list constructor should look similar, because they are supposed=
to perform an=20
itemwise initialization, while initialization with () is commonly used=20
for an arbitrary initialization. This is one of the reasons why I don't=20
like suggested {c:} and {l:}.</div><br>On Monday, January 28, 2013 8:26:50 =
AM UTC+4, vattila...@yahoo.co.uk wrote:<blockquote class=3D"gmail_quote" st=
yle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-lef=
t: 1ex;">So, in the case the il-preference rule was revoked, then vect=
or <int> ({42}) would not be sufficient to disambiguate in favou=
r of the il-constructor. But you could do<div> </div><div>vector <i=
nt> a =3D {42}; // OK: Pass single element (copy-initialization excludes=
explict constructors).</div></blockquote><div><br>1) Explicit constructors=
are still considered here.<br><br>2) In the following case<br><br> &n=
bsp; vector <int> a =3D {42, 1};<br><br>there are two viable co=
nverting constructors.<br><br>3) There are constructs (such as new-expressi=
ons and mem-initializers) where only direct-initialization is available.<br=
><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left=
: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div></div><div>or<=
/div><div> </div><div>vector <int> a (initializer_list <int&g=
t; {42}); // OK: Pass single element.</div><div> </div><div>Which is a=
mouthful</div></blockquote><div><br>while list-initializaiton is supposed =
to be terse :-)<br></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
To unsubscribe from this group, send email to std-proposals+unsubscribe@iso=
cpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_563_9673106.1359375571043--
.
Author: Sebastian Gesemann <s.gesemann@gmail.com>
Date: Mon, 28 Jan 2013 15:30:54 +0100
Raw View
Nicol Bolas wrote:
> [...]
I'm sorry, I still don't get it. How can the use of
T {l: ...}
T {c: ...}
instead of
T {...}
T (...)
be considered more uniform? It does not appear to solve any problem.
What did I miss?
Cheers!
SG
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To post to this group, send email to std-proposals@isocpp.org.
To unsubscribe from this group, send email to std-proposals+unsubscribe@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Mon, 28 Jan 2013 16:58:50 -0800 (PST)
Raw View
------=_Part_467_1100235.1359421130384
Content-Type: text/plain; charset=ISO-8859-1
On Monday, January 28, 2013 6:30:54 AM UTC-8, Sebastian Gesemann wrote:
>
> Nicol Bolas wrote:
> > [...]
>
> I'm sorry, I still don't get it. How can the use of
> T {l: ...}
> T {c: ...}
> instead of
> T {...}
> T (...)
> be considered more uniform? It does not appear to solve any problem.
> What did I miss?
>
You missed the fact that `T(...)` requires calling a constructor.
`T{c:...}` can use aggregate initialization if `T` is an aggregate.
The point is the ability to initialize aggregates or non-aggregates in the
exact same way. That's one of the big reasons uniform initialization syntax
exists. Also, there's the fact that you can't use `()` syntax without a
typename:
void Func(const std::vector &v) {...}
Func( (42) ); //Does not work.
Func( {42} ); //"works" but potentially does the wrong thing.
Func( {l: 42} ); //Does the right thing.
Func( {c:42} ); //Does work. Well, if it weren't an explicit constructor...
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_467_1100235.1359421130384
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Monday, January 28, 2013 6:30:54 AM UTC-8, Sebastian Gesemann wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">Nicol Bolas wrote:
<br>> [...]
<br>
<br>I'm sorry, I still don't get it. How can the use of
<br> T {l: ...}
<br> T {c: ...}
<br>instead of
<br> T {...}
<br> T (...)
<br>be considered more uniform? It does not appear to solve any problem.
<br>What did I miss?<br></blockquote><div><br>You missed the fact that `T(.=
...)` requires calling a constructor. `T{c:...}` can use aggregate initializ=
ation if `T` is an aggregate.<br><br>The point is the ability to initialize=
aggregates or non-aggregates in the exact same way. That's one of the big =
reasons uniform initialization syntax exists. Also, there's the fact that y=
ou can't use `()` syntax without a typename:<br><br><div class=3D"prettypri=
nt" style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 1=
87, 187); border-style: solid; border-width: 1px; word-wrap: break-word;"><=
code class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">void</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #606;" clas=
s=3D"styled-by-prettify">Func</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">(</span><span style=3D"color: #008;" class=3D"styled-by-=
prettify">const</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> std</span><span style=3D"color: #660;" class=3D"styled-by-prettify">:=
:</span><span style=3D"color: #000;" class=3D"styled-by-prettify">vector </=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">&</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify">v</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">{...}</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br><br></span><span style=3D"color: #606;" class=
=3D"styled-by-prettify">Func</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
(</span><span style=3D"color: #066;" class=3D"styled-by-prettify">42</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> </span><span style=3D"color: #800;" class=
=3D"styled-by-prettify">//Does not work.</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"><br></span><code class=3D"prettyprint"><span =
style=3D"color: #606;" class=3D"styled-by-prettify">Func</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">{</span><span style=3D"color: #066;" class=3D"=
styled-by-prettify">42</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">}</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span =
style=3D"color: #800;" class=3D"styled-by-prettify">//"works" but potential=
ly does the wrong thing.</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"><br></span><span style=3D"color: #606;" class=3D"styled-by-pr=
ettify"></span></code><code class=3D"prettyprint"><span style=3D"color: #60=
6;" class=3D"styled-by-prettify">Func</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">{l: </span><span style=3D"color: #066;" class=3D"styled-by-prettif=
y">42</span><span style=3D"color: #660;" class=3D"styled-by-prettify">}</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #=
800;" class=3D"styled-by-prettify">//Does the right thing.</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"c=
olor: #606;" class=3D"styled-by-prettify"></span></code><span style=3D"colo=
r: #606;" class=3D"styled-by-prettify">Func</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify">c</span><span style=3D"color: #660;" class=3D"styled-by-prettify">:</=
span><span style=3D"color: #066;" class=3D"styled-by-prettify">42</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"> </span><span style=3D"color: #800;" class=3D=
"styled-by-prettify">//Does work. Well, if it weren't an explicit construct=
or...</span></div></code></div><br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_467_1100235.1359421130384--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Mon, 28 Jan 2013 17:04:06 -0800 (PST)
Raw View
------=_Part_586_4389875.1359421446467
Content-Type: text/plain; charset=ISO-8859-1
On Monday, January 28, 2013 4:19:30 AM UTC-8, Nikolay Ivchenkov wrote:
>
> On Saturday, January 26, 2013 11:53:48 PM UTC+4, vattila...@yahoo.co.ukwrote:
>>
>>
>> > You can't initialize aggregates with ()
>>
>> Perhaps this warrants special consideration? Is there any reason why this
>> should not be allowed? E.g:
>>
>> struct Abc {int a, b, c;};
>> Abc abc (1, 2, 3);
>>
>> Conceptually, the language only needs to add an implicit constructor.
>> This would solve the emplace_back problem you demonstrated, I presume.
>>
>
> I think that aggregate initialization and initialization by an
> initializer-list constructor should look similar, because they are supposed
> to perform an itemwise initialization, while initialization with () is
> commonly used for an arbitrary initialization.
>
Except that it isn't; it's *only* used for calling constructors. It can't
initialize aggregates. Also, "commonly" is something that we are trying to *
change* with uniform initialization.
> This is one of the reasons why I don't like suggested {c:} and {l:}.
>
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_586_4389875.1359421446467
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Monday, January 28, 2013 4:19:30 AM UTC-8, Nikolay Ivchenkov wro=
te:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;">On Saturday, January 26, 20=
13 11:53:48 PM UTC+4, <a>vattila...@yahoo.co.uk</a> wrote:<blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><br><div style=3D"margin-bottom:0cm">
> You can't
initialize aggregates with ()</div><div style=3D"margin-bottom:0cm"><br>
Perhaps this warrants
special consideration? Is there any reason why this should not be
allowed? E.g:</div><div style=3D"margin-bottom:0cm"><br>
struct Abc {int a, b,
c;};</div>
<div style=3D"margin-bottom:0cm">Abc abc (1, 2, 3);</div><div style=3D"marg=
in-bottom:0cm"><br>
Conceptually, the
language only needs to add an implicit constructor. This would solve
the emplace_back problem you demonstrated, I presume.</div></blockquote><di=
v><br>I
think that aggregate initialization and initialization by an=20
initializer-list constructor should look similar, because they are supposed=
to perform an=20
itemwise initialization, while initialization with () is commonly used=20
for an arbitrary initialization.</div></blockquote><div><br>Except that it =
isn't; it's <i>only</i> used for calling constructors. It can't initialize =
aggregates. Also, "commonly" is something that we are trying to <i>change</=
i> with uniform initialization.<br> </div><blockquote class=3D"gmail_q=
uote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pad=
ding-left: 1ex;"><div>This is one of the reasons why I don't=20
like suggested {c:} and {l:}.<br></div></blockquote><br>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_586_4389875.1359421446467--
.
Author: Malte Skarupke <malteskarupke@gmail.com>
Date: Mon, 28 Jan 2013 23:46:20 -0500
Raw View
--f46d04447df768caa704d4661424
Content-Type: text/plain; charset=ISO-8859-1
I think I have a solution that doesn't require a new syntax.
What I would propose is that the list-initialization preference is dropped
for template types. For non-template types and for fully specialized
templates we keep the current rules.
That is all. I think that solves this problem cleanly.
What this means is that you can write this:
template<typename T, typename... Arguments>
T construct_uniform(Arguments &&... arguments)
{
// we don't know the type of T, so this will not prefer
initializer_list construction
return T{std::forward<Arguments>(arguments)...};
}
And it does what you expect.
For example
construct_uniform<std::vector<float>>(10); // create vector with ten
elements
construct_uniform<std::vector<int>>(10); // create vector with ten elements
construct_uniform<std::vector<int>>({10}); // create vector with one element
std::vector<float> ten_floats{10}; // create vector with ten elements
std::vector<int> one_int{10}; // create vector with one element
With the idea being that you know what you are doing when you are writing
code with fully specialized types. And that it's usually much easier to
change code that uses fully specialized objects if it doesn't do what you
expect it to do.
Imagine that you use a std::vector that uses an allocator that uses
something similar to that construct function. (I bet several code bases
have already started doing that to benefit from uniform initialization) And
you use it all over your code to store aggregates. And then you use it with
a std::deque<boost::any> for the first time. Which you can't copy using
uniform initialization. There would be no good way to fix that, because
your templated code is already used in too many places. My change would
make sure that there wouldn't be a problem to begin with.
All other rules for example about ambiguity remain unchanged. The reason
why construct_uniform<std::vector<int>>(10); is not ambiguous is that the
constructor using initializer lists would require a user defined conversion.
Also note that partial specializations do also not prefer initializer list
construction. So std::vector<T> ten{10}; Will always contain ten elements,
no matter what T is. Only fully specialized templates and non-template
types would prefer initializer list construction.
I think this doesn't break any existing code. If it does, the existing code
probably didn't do what you expected it to do anyway.
The one problem that this would still have is this:
construct_uniform<std::vector<int>>(10); // create vector with ten elements
construct_uniform<std::vector<int>>(10, 20, 30); // create vector with
three elements
I think that that is OK because it is easy to change this for the user (add
{}) and is a better problem to have than the current situation. Because
really at the moment you shouldn't use uniform initialization at all as
soon as templates are involved. Because it may break on some type that you
don't know about yet and then you won't be able to change it any more
because that would break your code for other types.
So what do you guys think? Did I miss that this would break something
obvious?
2013/1/28 Nicol Bolas <jmckesson@gmail.com>
>
>
> On Monday, January 28, 2013 4:19:30 AM UTC-8, Nikolay Ivchenkov wrote:
>>
>> On Saturday, January 26, 2013 11:53:48 PM UTC+4, vattila...@yahoo.co.ukwrote:
>>>
>>>
>>> > You can't initialize aggregates with ()
>>>
>>> Perhaps this warrants special consideration? Is there any reason why
>>> this should not be allowed? E.g:
>>>
>>> struct Abc {int a, b, c;};
>>> Abc abc (1, 2, 3);
>>>
>>> Conceptually, the language only needs to add an implicit constructor.
>>> This would solve the emplace_back problem you demonstrated, I presume.
>>>
>>
>> I think that aggregate initialization and initialization by an
>> initializer-list constructor should look similar, because they are supposed
>> to perform an itemwise initialization, while initialization with () is
>> commonly used for an arbitrary initialization.
>>
>
> Except that it isn't; it's *only* used for calling constructors. It can't
> initialize aggregates. Also, "commonly" is something that we are trying to
> *change* with uniform initialization.
>
>
>> This is one of the reasons why I don't like suggested {c:} and {l:}.
>>
>
> --
>
> ---
> 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.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
>
>
>
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
--f46d04447df768caa704d4661424
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
I think I have a solution that doesn't require a new syntax.<br><br>Wha=
t
I would propose is that the list-initialization preference is dropped for =
template types. For non-template types and for fully=20
specialized templates we keep the current rules.<br><br>That is all. I thin=
k that solves this problem cleanly.<br><br>What this means is that you can =
write this:<br><br>template<typename T, typename... Arguments><br>
T construct_uniform(Arguments &&... arguments)<br>{<br>=A0=A0=A0 //=
we don't know the type of T, so this will not prefer initializer_list =
construction<br>=A0=A0=A0 return T{std::forward<Arguments>(arguments)=
....};<br>
}<br><br>And it does what you expect.<br><br>For example<br>construct_unifo=
rm<std::vector<float>>(10); // create vector with ten elements<=
br>construct_uniform<std::vector<int>>(10); // create vector wi=
th ten elements<br>
construct_uniform<std::vector<int>>({10}); // create vector wit=
h one element<br>std::vector<float> ten_floats{10}; // create vector =
with ten elements<br>std::vector<int> one_int{10}; // create vector w=
ith one element<br>
<br>With the idea being that you know what you are doing when you are writi=
ng code with fully specialized types. And that it's usually much easier=
to change code that uses fully specialized objects if it doesn't do wh=
at you expect it to do.<br>
Imagine that you use a std::vector that uses an allocator that uses somethi=
ng similar to that construct function. (I bet several code bases have alrea=
dy started doing that to benefit from uniform initialization) And you use i=
t all over your code to store aggregates. And then you use it with a std::d=
eque<boost::any> for the first time. Which you can't copy using u=
niform initialization. There would be no good way to fix that, because your=
templated code is already used in too many places. My change would make su=
re that there wouldn't be a problem to begin with.<br>
<br>All other rules for example about ambiguity remain unchanged. The reaso=
n why construct_uniform<std::vector<int>>(10); is not ambiguous=
is that the constructor using initializer lists would require a user defin=
ed conversion.<br>
<br>Also note that partial specializations do also not prefer initializer l=
ist construction. So std::vector<T> ten{10}; Will always contain ten =
elements, no matter what T is. Only fully specialized templates and non-tem=
plate types would prefer initializer list construction.<br>
<br>I think this doesn't break any existing code. If it does, the exist=
ing code probably didn't do what you expected it to do anyway.<br><br>T=
he one problem that this would still have is this:<br>construct_uniform<=
std::vector<int>>(10); // create vector with ten elements<br>
construct_uniform<std::vector<int>>(10, 20, 30); // create vect=
or with three elements<br><br>I think that that is OK because it is easy to=
change this for the user (add {}) and is a better problem to have than the=
current situation. Because really at the moment you shouldn't use unif=
orm initialization at all as soon as templates are involved. Because it may=
break on some type that you don't know about yet and then you won'=
t be able to change it any more because that would break your code for othe=
r types.<br>
<br>So what do you guys think? Did I miss that this would break something o=
bvious?<br><br><div class=3D"gmail_quote">2013/1/28 Nicol Bolas <span dir=
=3D"ltr"><<a href=3D"mailto:jmckesson@gmail.com" target=3D"_blank">jmcke=
sson@gmail.com</a>></span><br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div class=3D"im"><br><br>On Monday, January=
28, 2013 4:19:30 AM UTC-8, Nikolay Ivchenkov wrote:<blockquote class=3D"gm=
ail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;p=
adding-left:1ex">
On Saturday, January 26, 2013 11:53:48 PM UTC+4, <a>vattila...@yahoo.co.uk<=
/a> wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0=
..8ex;border-left:1px #ccc solid;padding-left:1ex"><br><div style=3D"margin-=
bottom:0cm">
> You can't
initialize aggregates with ()</div><div style=3D"margin-bottom:0cm"><br>
Perhaps this warrants
special consideration? Is there any reason why this should not be
allowed? E.g:</div><div style=3D"margin-bottom:0cm"><br>
struct Abc {int a, b,
c;};</div>
<div style=3D"margin-bottom:0cm">Abc abc (1, 2, 3);</div><div style=3D"marg=
in-bottom:0cm"><br>
Conceptually, the
language only needs to add an implicit constructor. This would solve
the emplace_back problem you demonstrated, I presume.</div></blockquote><di=
v><br>I
think that aggregate initialization and initialization by an=20
initializer-list constructor should look similar, because they are supposed=
to perform an=20
itemwise initialization, while initialization with () is commonly used=20
for an arbitrary initialization.</div></blockquote></div><div><br>Except th=
at it isn't; it's <i>only</i> used for calling constructors. It can=
't initialize aggregates. Also, "commonly" is something that =
we are trying to <i>change</i> with uniform initialization.<br>
=A0</div><div class=3D"im HOEnZb"><blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div>This is one of the reasons why I don't=20
like suggested {c:} and {l:}.<br></div></blockquote><br>
<p></p></div><div class=3D"im HOEnZb">
-- <br>
=A0<br>
--- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br></div><div class=
=3D"im HOEnZb">
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals%2Bunsubscribe@isocpp.org" target=3D=
"_blank">std-proposals+unsubscribe@isocpp.org</a>.<br></div><div class=3D"i=
m HOEnZb">
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></div><div class=
=3D"HOEnZb"><div class=3D"h5">
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den" target=3D"_blank">http://groups.google.com/a/isocpp=
..org/group/std-proposals/?hl=3Den</a>.<br>
=A0<br>
=A0<br>
</div></div></blockquote></div><br>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
--f46d04447df768caa704d4661424--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Mon, 28 Jan 2013 21:37:36 -0800 (PST)
Raw View
------=_Part_1283_2420360.1359437856319
Content-Type: text/plain; charset=ISO-8859-1
On Monday, January 28, 2013 8:46:20 PM UTC-8, Malte Skarupke wrote:
>
> I think I have a solution that doesn't require a new syntax.
>
> What I would propose is that the list-initialization preference is dropped
> for template types. For non-template types and for fully specialized
> templates we keep the current rules.
>
> That is all. I think that solves this problem cleanly.
>
> What this means is that you can write this:
>
> template<typename T, typename... Arguments>
> T construct_uniform(Arguments &&... arguments)
> {
> // we don't know the type of T, so this will not prefer
> initializer_list construction
> return T{std::forward<Arguments>(arguments)...};
> }
>
> And it does what you expect.
>
> For example
> construct_uniform<std::vector<float>>(10); // create vector with ten
> elements
> construct_uniform<std::vector<int>>(10); // create vector with ten elements
> construct_uniform<std::vector<int>>({10}); // create vector with one
> element
> std::vector<float> ten_floats{10}; // create vector with ten elements
> std::vector<int> one_int{10}; // create vector with one element
>
> With the idea being that you know what you are doing when you are writing
> code with fully specialized types.
So instead of a short-and-simple language feature that's compact and easy
to read, you want a big, bulky *library* feature that's connected to a
language feature.
We can almost implement `construct_uniform` now, using `std::enable_if`
(assuming that we get a `std::is_aggregate` traits class):
template<typename T, typename... Arguments>
typename std::enable_if<std::is_aggregate<T>::value, T>::type
construct_uniform(Arguments &&... arguments)
{
//T is an aggregate, so use uniform initialization.
return T{std::forward<Arguments>(arguments)...};
}
template<typename T, typename... Arguments>
typename std::enable_if<!std::is_aggregate<T>::value, T>::type
construct_uniform(Arguments &&... arguments)
{
//T is not an aggregate, so call a constructor.
return T(std::forward<Arguments>(arguments)...);
}
The problem is that you can't use `construct_uniform` in any context. You *
must* name the type T, so you're not able to get the equivalent of this:
SomeFunc(arg1, {c:...}, arg3);
If `SomeFunc`'s second parameter is type-deduced, then this code (using {})
would fail, because you can't use braced-init-lists with type deduction
contexts. Or at least, not for a general `T`-style argument. And if it's
not type deduced, then using {} syntax would give the inconsistent results
above. Your resolution for this would be:
SomeFunc(arg1, construct_uniform(...), arg3);
Which gets in the way of the whole "not having to repeat the typename that
the compiler can easily deduce" issue.
So no, this is not as good a solution; it only solves part of the problem.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_1283_2420360.1359437856319
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Monday, January 28, 2013 8:46:20 PM UTC-8, Malte Skarupke wrote:=
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bor=
der-left: 1px #ccc solid;padding-left: 1ex;">I think I have a solution that=
doesn't require a new syntax.<br><br>What
I would propose is that the list-initialization preference is dropped for =
template types. For non-template types and for fully=20
specialized templates we keep the current rules.<br><br>That is all. I thin=
k that solves this problem cleanly.<br><br>What this means is that you can =
write this:<br><br>template<typename T, typename... Arguments><br>
T construct_uniform(Arguments &&... arguments)<br>{<br> =
// we don't know the type of T, so this will not prefer initializer_=
list construction<br> return T{std::forward<Arguments&=
gt;(<wbr>arguments)...};<br>
}<br><br>And it does what you expect.<br><br>For example<br>construct_unifo=
rm<std::vector<<wbr>float>>(10); // create vector with ten elem=
ents<br>construct_uniform<std::vector<<wbr>int>>(10); // create=
vector with ten elements<br>
construct_uniform<std::vector<<wbr>int>>({10}); // create vecto=
r with one element<br>std::vector<float> ten_floats{10}; // create ve=
ctor with ten elements<br>std::vector<int> one_int{10}; // create vec=
tor with one element<br>
<br>With the idea being that you know what you are doing when you are writi=
ng code with fully specialized types.</blockquote><div><br>So instead of a =
short-and-simple language feature that's compact and easy to read, you want=
a big, bulky <i>library</i> feature that's connected to a language feature=
..<br><br>We can almost implement `construct_uniform` now, using `std::enabl=
e_if` (assuming that we get a `std::is_aggregate` traits class):<br><br><di=
v class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); bord=
er-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-=
wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint=
"><span style=3D"color: #008;" class=3D"styled-by-prettify">template</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span =
style=3D"color: #008;" class=3D"styled-by-prettify">typename</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> T</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">typename</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">...</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-pr=
ettify">Arguments</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">></span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify">typen=
ame</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> std</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify">enable_if</span><span=
style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">std</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify">is_aggregate</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify"><</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify">T</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">>::</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">value</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> T</span><span style=3D"color: #660;" class=3D"styled-by-prettify">>::<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify">type constr=
uct_uniform</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>(</span><span style=3D"color: #606;" class=3D"styled-by-prettify">Argument=
s</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">&&...</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> arguments</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br> </span><span style=3D"colo=
r: #800;" class=3D"styled-by-prettify">//T is an aggregate, so use uniform =
initialization.</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"><br> </span><span style=3D"color: #008;" class=3D"styled-by-pret=
tify">return</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> T</span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify">std</span><span=
style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">forward</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify"><</span><span style=3D"color=
: #606;" class=3D"styled-by-prettify">Arguments</span><span style=3D"color:=
#660;" class=3D"styled-by-prettify">>(</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify">arguments</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">)...};</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">}</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"><br><br></span><span style=3D"color: #008;" class=3D"styled-by-=
prettify">template</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify"><</span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">typename</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
T</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">typename</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">...</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #606;=
" class=3D"styled-by-prettify">Arguments</span><span style=3D"color: #660;"=
class=3D"styled-by-prettify">></span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">typename</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> std</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
">enable_if</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
><!</span><span style=3D"color: #000;" class=3D"styled-by-prettify">std<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify">is_aggregate</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify">T</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">>::</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">value</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> T</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">>::</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify">type construct_uniform</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">(</span><span style=3D"color: #606;" class=3D"styl=
ed-by-prettify">Arguments</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">&&...</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> arguments</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">)</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
<br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"><br> </sp=
an><span style=3D"color: #800;" class=3D"styled-by-prettify">//T is not an =
aggregate, so call a constructor.</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br> </span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">return</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> T</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy">std</span><span style=3D"color: #660;" class=3D"styled-by-prettify">::<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify">forward</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify"><</span><sp=
an style=3D"color: #606;" class=3D"styled-by-prettify">Arguments</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">>(</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify">arguments</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">)...);</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">}</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br></span></div></code></div><br>The problem =
is that you can't use `construct_uniform` in any context. You <i>must</i> n=
ame the type T, so you're not able to get the equivalent of this:<br><br><d=
iv class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); bor=
der-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; word=
-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprin=
t"><span style=3D"color: #606;" class=3D"styled-by-prettify">SomeFunc</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify">arg1</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify">c</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">:...},</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> arg3</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)=
;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></spa=
n></div></code></div><br>If `SomeFunc`'s second parameter is type-deduced, =
then this code (using {}) would fail, because you can't use braced-init-lis=
ts with type deduction contexts. Or at least, not for a general `T`-style a=
rgument. And if it's not type deduced, then using {} syntax would give the =
inconsistent results above. Your resolution for this would be:<br><br>SomeF=
unc(arg1, construct_uniform(...), arg3);<br><br>Which gets in the way of th=
e whole "not having to repeat the typename that the compiler can easily ded=
uce" issue.<br><br>So no, this is not as good a solution; it only solves pa=
rt of the problem.</div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_1283_2420360.1359437856319--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Tue, 29 Jan 2013 02:34:15 -0800 (PST)
Raw View
------=_Part_103_14516096.1359455655707
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, January 29, 2013 5:04:06 AM UTC+4, Nicol Bolas wrote:
> On Monday, January 28, 2013 4:19:30 AM UTC-8, Nikolay Ivchenkov wrote:
>>
>>
>> I think that aggregate initialization and initialization by an
>> initializer-list constructor should look similar, because they are supposed
>> to perform an itemwise initialization, while initialization with () is
>> commonly used for an arbitrary initialization.
>>
>
> Except that it isn't; it's *only* used for calling constructors.
>
And such constructors may perform a non-itemwise initialization.
> It can't initialize aggregates.
>
Actually it can initialize aggregates, but only with another instance:
#include <iostream>
#include <string>
struct A
{
std::string s;
int n;
};
int main()
{
A a({"text", 1});
std::cout << a.s << "; " << a.n << std::endl;
}
Here 'a' initialized with a temporary object, which is initialized with the
braced-init-list. It's possible to modify the rules so that
AggregateType({items...}) would be equivalent to AggregateType{items...}.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_103_14516096.1359455655707
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Tuesday, January 29, 2013 5:04:06 AM UTC+4, Nicol Bolas wrote:<br><block=
quote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-le=
ft: 1px #ccc solid;padding-left: 1ex;">On Monday, January 28, 2013 4:19:30 =
AM UTC-8, Nikolay Ivchenkov wrote:<blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div><br>I
think that aggregate initialization and initialization by an=20
initializer-list constructor should look similar, because they are supposed=
to perform an=20
itemwise initialization, while initialization with () is commonly used=20
for an arbitrary initialization.</div></blockquote><div><br>Except that it =
isn't; it's <i>only</i> used for calling constructors.</div></blockquote><d=
iv><br>And such constructors may perform a non-itemwise initialization.<br>=
</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div> It can't ini=
tialize aggregates.</div></blockquote><div><br>Actually it can initialize a=
ggregates, but only with another instance:<br><br> #inclu=
de <iostream><br> #include <string><br> =
<br> struct A<br> {<br> &nb=
sp; std::string s;<br>  =
; int n;<br> };<br> <br>&nb=
sp; int main()<br> {<br> &nb=
sp; A a({"text", 1});<br> &n=
bsp; std::cout << a.s << "; " << a.n << std::=
endl;<br> }<br><br>Here 'a' initialized with a temporary =
object, which is initialized with the braced-init-list. It's possible to mo=
dify the rules so that AggregateType({items...}) would be equivalent to Agg=
regateType{items...}.</div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_103_14516096.1359455655707--
.
Author: Malte Skarupke <malteskarupke@gmail.com>
Date: Tue, 29 Jan 2013 07:04:42 -0500
Raw View
--047d7bf19890e960ec04d46c32d6
Content-Type: text/plain; charset=ISO-8859-1
The construct_uniform was just an example to illustrate the effects of my
proposed change. It is not part of the proposal.
The proposal is to drop the list initialization preference for template
types and partially specialized templates. Non-template types and fully
specialized templates keep the current behavior.
Now read that email again for examples.
You will find that that change solves all the problems mentioned in this
thread without requiring new syntax.
Yes, it would mean that you have to fall back to () initialization
sometimes, (as you do now) but it is superior to the current uniform
initialization rules in that it doesn't give you unexpected behavior.
Am 29.01.2013 00:37 schrieb "Nicol Bolas" <jmckesson@gmail.com>:
>
>
> On Monday, January 28, 2013 8:46:20 PM UTC-8, Malte Skarupke wrote:
>>
>> I think I have a solution that doesn't require a new syntax.
>>
>> What I would propose is that the list-initialization preference is
>> dropped for template types. For non-template types and for fully
>> specialized templates we keep the current rules.
>>
>> That is all. I think that solves this problem cleanly.
>>
>> What this means is that you can write this:
>>
>> template<typename T, typename... Arguments>
>> T construct_uniform(Arguments &&... arguments)
>> {
>> // we don't know the type of T, so this will not prefer
>> initializer_list construction
>> return T{std::forward<Arguments>(**arguments)...};
>> }
>>
>> And it does what you expect.
>>
>> For example
>> construct_uniform<std::vector<**float>>(10); // create vector with ten
>> elements
>> construct_uniform<std::vector<**int>>(10); // create vector with ten
>> elements
>> construct_uniform<std::vector<**int>>({10}); // create vector with one
>> element
>> std::vector<float> ten_floats{10}; // create vector with ten elements
>> std::vector<int> one_int{10}; // create vector with one element
>>
>> With the idea being that you know what you are doing when you are writing
>> code with fully specialized types.
>
>
> So instead of a short-and-simple language feature that's compact and easy
> to read, you want a big, bulky *library* feature that's connected to a
> language feature.
>
> We can almost implement `construct_uniform` now, using `std::enable_if`
> (assuming that we get a `std::is_aggregate` traits class):
>
> template<typename T, typename... Arguments>
> typename std::enable_if<std::is_aggregate<T>::value, T>::type
> construct_uniform(Arguments &&... arguments)
> {
> //T is an aggregate, so use uniform initialization.
> return T{std::forward<Arguments>(arguments)...};
> }
>
> template<typename T, typename... Arguments>
> typename std::enable_if<!std::is_aggregate<T>::value, T>::type
> construct_uniform(Arguments &&... arguments)
> {
> //T is not an aggregate, so call a constructor.
> return T(std::forward<Arguments>(arguments)...);
> }
>
> The problem is that you can't use `construct_uniform` in any context. You
> *must* name the type T, so you're not able to get the equivalent of this:
>
> SomeFunc(arg1, {c:...}, arg3);
>
> If `SomeFunc`'s second parameter is type-deduced, then this code (using
> {}) would fail, because you can't use braced-init-lists with type deduction
> contexts. Or at least, not for a general `T`-style argument. And if it's
> not type deduced, then using {} syntax would give the inconsistent results
> above. Your resolution for this would be:
>
> SomeFunc(arg1, construct_uniform(...), arg3);
>
> Which gets in the way of the whole "not having to repeat the typename that
> the compiler can easily deduce" issue.
>
> So no, this is not as good a solution; it only solves part of the problem.
>
> --
>
> ---
> 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.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
>
>
>
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
--047d7bf19890e960ec04d46c32d6
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<p>The construct_uniform was just an example to illustrate the effects of m=
y proposed change. It is not part of the proposal.</p>
<p>The proposal is to drop the list initialization preference for template =
types and partially specialized templates. Non-template types and fully spe=
cialized templates keep the current behavior.</p>
<p>Now read that email again for examples.<br>
You will find that that change solves all the problems mentioned in this th=
read without requiring new syntax.</p>
<p>Yes, it would mean that you have to fall back to () initialization somet=
imes, (as you do now) but it is superior to the current uniform initializat=
ion rules in that it doesn't give you unexpected behavior.</p>
<div class=3D"gmail_quote">Am 29.01.2013 00:37 schrieb "Nicol Bolas&qu=
ot; <<a href=3D"mailto:jmckesson@gmail.com">jmckesson@gmail.com</a>>:=
<br type=3D"attribution"><blockquote class=3D"gmail_quote" style=3D"margin:=
0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br><br>On Monday, January 28, 2013 8:46:20 PM UTC-8, Malte Skarupke wrote:=
<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;borde=
r-left:1px #ccc solid;padding-left:1ex">I think I have a solution that does=
n't require a new syntax.<br>
<br>What
I would propose is that the list-initialization preference is dropped for =
template types. For non-template types and for fully=20
specialized templates we keep the current rules.<br><br>That is all. I thin=
k that solves this problem cleanly.<br><br>What this means is that you can =
write this:<br><br>template<typename T, typename... Arguments><br>
T construct_uniform(Arguments &&... arguments)<br>{<br>=A0=A0=A0 //=
we don't know the type of T, so this will not prefer initializer_list =
construction<br>=A0=A0=A0 return T{std::forward<Arguments>(<u></u>arg=
uments)...};<br>
}<br><br>And it does what you expect.<br><br>For example<br>construct_unifo=
rm<std::vector<<u></u>float>>(10); // create vector with ten el=
ements<br>construct_uniform<std::vector<<u></u>int>>(10); // cr=
eate vector with ten elements<br>
construct_uniform<std::vector<<u></u>int>>({10}); // create vec=
tor with one element<br>std::vector<float> ten_floats{10}; // create =
vector with ten elements<br>std::vector<int> one_int{10}; // create v=
ector with one element<br>
<br>With the idea being that you know what you are doing when you are writi=
ng code with fully specialized types.</blockquote><div><br>So instead of a =
short-and-simple language feature that's compact and easy to read, you =
want a big, bulky <i>library</i> feature that's connected to a language=
feature.<br>
<br>We can almost implement `construct_uniform` now, using `std::enable_if`=
(assuming that we get a `std::is_aggregate` traits class):<br><br><div sty=
le=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);borde=
r-style:solid;border-width:1px;word-wrap:break-word">
<code><div><span style=3D"color:#008">template</span><span style=3D"color:#=
660"><</span><span style=3D"color:#008">typename</span><span style> T</s=
pan><span style=3D"color:#660">,</span><span style> </span><span style=3D"c=
olor:#008">typename</span><span style=3D"color:#660">...</span><span style>=
</span><span style=3D"color:#606">Arguments</span><span style=3D"color:#66=
0">></span><span style><br>
</span><span style=3D"color:#008">typename</span><span style> std</span><sp=
an style=3D"color:#660">::</span><span style>enable_if</span><span style=3D=
"color:#660"><</span><span style>std</span><span style=3D"color:#660">::=
</span><span style>is_aggregate</span><span style=3D"color:#660"><</span=
><span style>T</span><span style=3D"color:#660">>::</span><span style>va=
lue</span><span style=3D"color:#660">,</span><span style> T</span><span sty=
le=3D"color:#660">>::</span><span style>type construct_uniform</span><sp=
an style=3D"color:#660">(</span><span style=3D"color:#606">Arguments</span>=
<span style> </span><span style=3D"color:#660">&&...</span><span st=
yle> arguments</span><span style=3D"color:#660">)</span><span style><br>
</span><span style=3D"color:#660">{</span><span style><br>=A0 </span><span =
style=3D"color:#800">//T is an aggregate, so use uniform initialization.</s=
pan><span style><br>=A0 </span><span style=3D"color:#008">return</span><spa=
n style> T</span><span style=3D"color:#660">{</span><span style>std</span><=
span style=3D"color:#660">::</span><span style>forward</span><span style=3D=
"color:#660"><</span><span style=3D"color:#606">Arguments</span><span st=
yle=3D"color:#660">>(</span><span style>arguments</span><span style=3D"c=
olor:#660">)...};</span><span style><br>
</span><span style=3D"color:#660">}</span><span style><br><br></span><span =
style=3D"color:#008">template</span><span style=3D"color:#660"><</span><=
span style=3D"color:#008">typename</span><span style> T</span><span style=
=3D"color:#660">,</span><span style> </span><span style=3D"color:#008">type=
name</span><span style=3D"color:#660">...</span><span style> </span><span s=
tyle=3D"color:#606">Arguments</span><span style=3D"color:#660">></span><=
span style><br>
</span><span style=3D"color:#008">typename</span><span style> std</span><sp=
an style=3D"color:#660">::</span><span style>enable_if</span><span style=3D=
"color:#660"><!</span><span style>std</span><span style=3D"color:#660">:=
:</span><span style>is_aggregate</span><span style=3D"color:#660"><</spa=
n><span style>T</span><span style=3D"color:#660">>::</span><span style>v=
alue</span><span style=3D"color:#660">,</span><span style> T</span><span st=
yle=3D"color:#660">>::</span><span style>type construct_uniform</span><s=
pan style=3D"color:#660">(</span><span style=3D"color:#606">Arguments</span=
><span style> </span><span style=3D"color:#660">&&...</span><span s=
tyle> arguments</span><span style=3D"color:#660">)</span><span style><br>
</span><span style=3D"color:#660">{</span><span style><br>=A0 </span><span =
style=3D"color:#800">//T is not an aggregate, so call a constructor.</span>=
<span style><br>=A0 </span><span style=3D"color:#008">return</span><span st=
yle> T</span><span style=3D"color:#660">(</span><span style>std</span><span=
style=3D"color:#660">::</span><span style>forward</span><span style=3D"col=
or:#660"><</span><span style=3D"color:#606">Arguments</span><span style=
=3D"color:#660">>(</span><span style>arguments</span><span style=3D"colo=
r:#660">)...);</span><span style><br>
</span><span style=3D"color:#660">}</span><span style><br></span></div></co=
de></div><br>The problem is that you can't use `construct_uniform` in a=
ny context. You <i>must</i> name the type T, so you're not able to get =
the equivalent of this:<br>
<br><div style=3D"background-color:rgb(250,250,250);border-color:rgb(187,18=
7,187);border-style:solid;border-width:1px;word-wrap:break-word"><code><div=
><span style=3D"color:#606">SomeFunc</span><span style=3D"color:#660">(</sp=
an><span style>arg1</span><span style=3D"color:#660">,</span><span style> <=
/span><span style=3D"color:#660">{</span><span style>c</span><span style=3D=
"color:#660">:...},</span><span style> arg3</span><span style=3D"color:#660=
">);</span><span style><br>
</span></div></code></div><br>If `SomeFunc`'s second parameter is type-=
deduced, then this code (using {}) would fail, because you can't use br=
aced-init-lists with type deduction contexts. Or at least, not for a genera=
l `T`-style argument. And if it's not type deduced, then using {} synta=
x would give the inconsistent results above. Your resolution for this would=
be:<br>
<br>SomeFunc(arg1, construct_uniform(...), arg3);<br><br>Which gets in the =
way of the whole "not having to repeat the typename that the compiler =
can easily deduce" issue.<br><br>So no, this is not as good a solution=
; it only solves part of the problem.</div>
<p></p>
-- <br>
=A0<br>
--- <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%2Bunsubscribe@isocpp.org" target=3D=
"_blank">std-proposals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den" target=3D"_blank">http://groups.google.com/a/isocpp=
..org/group/std-proposals/?hl=3Den</a>.<br>
=A0<br>
=A0<br>
</blockquote></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
--047d7bf19890e960ec04d46c32d6--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 29 Jan 2013 04:55:09 -0800 (PST)
Raw View
------=_Part_1550_14437516.1359464109246
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, January 29, 2013 4:04:42 AM UTC-8, Malte Skarupke wrote:
>
> The construct_uniform was just an example to illustrate the effects of my
> proposed change. It is not part of the proposal.
>
> The proposal is to drop the list initialization preference for template
> types and partially specialized templates. Non-template types and fully
> specialized templates keep the current behavior.
>
> Now read that email again for examples.
> You will find that that change solves all the problems mentioned in this
> thread without requiring new syntax.
>
Here's one it doesn't solve:
void SomeFunc(std::vector<int> v);
SomeFunc({10});
There's no type deduction happening here.
Yes, it would mean that you have to fall back to () initialization
> sometimes,
>
If you have to abandon uniform initialization syntax, it's not solving the
problem. It's *hiding* the problem. The proposal is called "Towards *more*uniform initialization", not less.
> (as you do now) but it is superior to the current uniform initialization
> rules in that it doesn't give you unexpected behavior.
>
But it *does* give unexpected behavior. It gives the same unexpected
behavior as it currently does in non-template deduction contexts. That's
how you defined it. So something as simple as this:
std::vector<int> v{20};
Does not get fixed. You still cannot access std::vector<int>'s sizing
constructor with uniform initialization syntax.
You're basically saying that it's safe(er) to use {} in templates, but not
in non-template code.
You're too focused on just the template issue. The fundamental issue is the
fact that the user has no ability to decide which constructors should be
preferable. Coming up with ad-hoc rules as you did is no solution; we tried
that with the current {} syntax, and it turns out that it didn't work. We
have to accept that the user needs a way to *explicitly* state whether a
particular braced-init-list should be used as an initializer list
constructor parameter or as arguments to a constructor.
Also, it should be noted that this is probably the first feature that has
been suggested where behavior of code changes based on the fact that a
named type just so happened to have come from a template rather than being
hard-coded. I don't like that idea; template code is not a special land
where the rules of C++ apply differently. It should work the same as
anywhere else.
Oh, and one more thing: it's a breaking change. Granted, it would only
break code that's somewhat dangerous anyway, but it's still a breaking
change. Mine isn't.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_1550_14437516.1359464109246
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Tuesday, January 29, 2013 4:04:42 AM UTC-8, Malte Skarupke wrote:<blockq=
uote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-lef=
t: 1px #ccc solid;padding-left: 1ex;"><p>The construct_uniform was just an =
example to illustrate the effects of my proposed change. It is not part of =
the proposal.</p>
<p>The proposal is to drop the list initialization preference for template =
types and partially specialized templates. Non-template types and fully spe=
cialized templates keep the current behavior.</p>
<p>Now read that email again for examples.<br>
You will find that that change solves all the problems mentioned in this th=
read without requiring new syntax.</p></blockquote><div>Here's one it doesn=
't solve:<br><br><div class=3D"prettyprint" style=3D"background-color: rgb(=
250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; bord=
er-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div cla=
ss=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-prett=
ify">void</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #606;" class=3D"styled-by-prettify">SomeFunc</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify">std</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">vector</span><span style=3D"color: #=
080;" class=3D"styled-by-prettify"><int></span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> v</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">);</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"><br><br></span><span style=3D"color: #606;" class=3D"st=
yled-by-prettify">SomeFunc</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">({</span><span style=3D"color: #066;" class=3D"styled-by-pr=
ettify">10</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
});</span></div></code></div><br>There's no type deduction happening here.<=
br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-le=
ft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<p>Yes, it would mean that you have to fall back to () initialization somet=
imes,</p></blockquote><div>If you have to abandon uniform initialization sy=
ntax, it's not solving the problem. It's <i>hiding</i> the problem. The pro=
posal is called "Towards <i>more</i> uniform initialization", not less.<br>=
</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><p> (as you do now=
) but it is superior to the current uniform initialization rules in that it=
doesn't give you unexpected behavior.</p></blockquote><div>But it <i>does<=
/i> give unexpected behavior. It gives the same unexpected behavior as it c=
urrently does in non-template deduction contexts. That's how you defined it=
.. So something as simple as this:<br><br><div class=3D"prettyprint" style=
=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187);=
border-style: solid; border-width: 1px; word-wrap: break-word;"><code clas=
s=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #000;=
" class=3D"styled-by-prettify">std</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">vector</span><span style=3D"color: #080;" class=3D"styled-b=
y-prettify"><int></span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> v</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">{</span><span style=3D"color: #066;" class=3D"styled-by-prettify">20</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">};</span></d=
iv></code></div><br>Does not get fixed. You still cannot access std::vector=
<int>'s sizing constructor with uniform initialization syntax.<br><br=
>You're basically saying that it's safe(er) to use {} in templates, but not=
in non-template code.<br><br>You're too focused on just the template issue=
.. The fundamental issue is the fact that the user has no ability to decide =
which constructors should be preferable. Coming up with ad-hoc rules as you=
did is no solution; we tried that with the current {} syntax, and it turns=
out that it didn't work. We have to accept that the user needs a way to <i=
>explicitly</i> state whether a particular braced-init-list should be used =
as an initializer list constructor parameter or as arguments to a construct=
or.<br><br>Also, it should be noted that this is probably the first feature=
that has been suggested where behavior of code changes based on the fact t=
hat a named type just so happened to have come from a template rather than =
being hard-coded. I don't like that idea; template code is not a special la=
nd where the rules of C++ apply differently. It should work the same as any=
where else.<br><br>Oh, and one more thing: it's a breaking change. Granted,=
it would only break code that's somewhat dangerous anyway, but it's still =
a breaking change. Mine isn't.<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_1550_14437516.1359464109246--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 29 Jan 2013 05:02:20 -0800 (PST)
Raw View
------=_Part_257_24464970.1359464540524
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, January 29, 2013 2:34:15 AM UTC-8, Nikolay Ivchenkov wrote:
>
> On Tuesday, January 29, 2013 5:04:06 AM UTC+4, Nicol Bolas wrote:
>
>> On Monday, January 28, 2013 4:19:30 AM UTC-8, Nikolay Ivchenkov wrote:
>>>
>>>
>>> I think that aggregate initialization and initialization by an
>>> initializer-list constructor should look similar, because they are supposed
>>> to perform an itemwise initialization, while initialization with () is
>>> commonly used for an arbitrary initialization.
>>>
>>
>> Except that it isn't; it's *only* used for calling constructors.
>>
>
> And such constructors may perform a non-itemwise initialization.
>
Uniform initialization syntax is not meant to be used only for "itemwise
initialization". It was, as stated in N2532, to be used in all cases of
initialization. The goal here is to make it usable in all cases of
initialization.
If you want to argue against this goal, take it up with Stroustrup.
>
>> It can't initialize aggregates.
>>
>
> Actually it can initialize aggregates, but only with another instance:
>
> #include <iostream>
> #include <string>
>
> struct A
> {
> std::string s;
> int n;
> };
>
> int main()
> {
> A a({"text", 1});
> std::cout << a.s << "; " << a.n << std::endl;
> }
>
> Here 'a' initialized with a temporary object, which is initialized with
> the braced-init-list. It's possible to modify the rules so that
> AggregateType({items...}) would be equivalent to AggregateType{items...}.
>
So you want to change the rules of how copy constructors for aggregates
work, but only in the case when the argument just so happens to be created
from a braced-init-list?
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_257_24464970.1359464540524
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Tuesday, January 29, 2013 2:34:15 AM UTC-8, Nikolay Ivchenkov wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">On Tuesday, January 29, 20=
13 5:04:06 AM UTC+4, Nicol Bolas wrote:<br><blockquote class=3D"gmail_quote=
" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-le=
ft:1ex">On Monday, January 28, 2013 4:19:30 AM UTC-8, Nikolay Ivchenkov wro=
te:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;bo=
rder-left:1px #ccc solid;padding-left:1ex"><div><br>I
think that aggregate initialization and initialization by an=20
initializer-list constructor should look similar, because they are supposed=
to perform an=20
itemwise initialization, while initialization with () is commonly used=20
for an arbitrary initialization.</div></blockquote><div><br>Except that it =
isn't; it's <i>only</i> used for calling constructors.</div></blockquote><d=
iv><br>And such constructors may perform a non-itemwise initialization.<br>=
</div></blockquote><div><br>Uniform initialization syntax is not meant to b=
e used only for "itemwise initialization". It was, as stated in N2532, to b=
e used in all cases of initialization. The goal here is to make it usable i=
n all cases of initialization.<br><br>If you want to argue against this goa=
l, take it up with Stroustrup.<br><br></div><blockquote class=3D"gmail_quot=
e" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddin=
g-left: 1ex;"><div> </div><blockquote class=3D"gmail_quote" style=3D"m=
argin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div=
> It can't initialize aggregates.</div></blockquote><div><br>Actually it ca=
n initialize aggregates, but only with another instance:<br><br>  =
; #include <iostream><br> #include <string=
><br> <br> struct A<br> =
{<br> std::string s;<br> &nb=
sp; int n;<br> };<br> =
<br> int main()<br> {<br> &=
nbsp; A a({"text", 1});<br> =
std::cout << a.s << "; " << a.n =
<< std::endl;<br> }<br><br>Here 'a' initialized wit=
h a temporary object, which is initialized with the braced-init-list. It's =
possible to modify the rules so that AggregateType({items...}) would be equ=
ivalent to AggregateType{items...}.</div></blockquote><div><br>So you want =
to change the rules of how copy constructors for aggregates work, but only =
in the case when the argument just so happens to be created from a braced-i=
nit-list?<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_257_24464970.1359464540524--
.
Author: Sebastian Gesemann <s.gesemann@gmail.com>
Date: Tue, 29 Jan 2013 14:11:18 +0100
Raw View
On Tue, Jan 29, 2013 at 1:58 AM, Nicol Bolas <jmckesson@gmail.com> wrote:
> On Monday, January 28, 2013 6:30:54 AM UTC-8, Sebastian Gesemann wrote:
>>
>> Nicol Bolas wrote:
>> > [...]
>>
>> I'm sorry, I still don't get it. How can the use of
>> T {l: ...}
>> T {c: ...}
>> instead of
>> T {...}
>> T (...)
>> be considered more uniform? It does not appear to solve any problem.
>> What did I miss?
>
> You missed the fact that `T(...)` requires calling a constructor. `T{c:...}`
> can use aggregate initialization if `T` is an aggregate.
> The point is the ability to initialize aggregates or non-aggregates in the
> exact same way.
If you don't care about whether T is an aggregate or not, what is
stopping you from using the plain C++11 curly braces for
initialization?
> Also, there's the fact that you can't use `()` syntax without a
> typename:
>
> void Func(const std::vector &v) {...}
>
> Func( (42) ); //Does not work.
This is a copy initialization context for 'v' and the constructor is
explicit. I hope nobody actually wants this to invoke the constructor
that takes a size parameter because that's the point of having
explicit constructors.
> Func( {42} ); //"works" but potentially does the wrong thing.
By "potentially does the wrong thing" I guess you mean that the
constructor taking a value for the size might be invoked by accident
here. If so, You are wrong on this one because this constructor is
explicit which is why it's not viable in this context.
> Func( {l: 42} ); //Does the right thing.
We don't need the explicit 'l:' in this case to make the compiler
prefer std::initializer_list constructors.
Cheers!
SG
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 29 Jan 2013 05:32:33 -0800 (PST)
Raw View
------=_Part_585_31164898.1359466353445
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, January 29, 2013 5:11:18 AM UTC-8, Sebastian Gesemann wrote:
>
> On Tue, Jan 29, 2013 at 1:58 AM, Nicol Bolas <jmck...@gmail.com<javascript:>>
> wrote:
> > On Monday, January 28, 2013 6:30:54 AM UTC-8, Sebastian Gesemann wrote:
> >>
> >> Nicol Bolas wrote:
> >> > [...]
> >>
> >> I'm sorry, I still don't get it. How can the use of
> >> T {l: ...}
> >> T {c: ...}
> >> instead of
> >> T {...}
> >> T (...)
> >> be considered more uniform? It does not appear to solve any problem.
> >> What did I miss?
> >
> > You missed the fact that `T(...)` requires calling a constructor.
> `T{c:...}`
> > can use aggregate initialization if `T` is an aggregate.
> > The point is the ability to initialize aggregates or non-aggregates in
> the
> > exact same way.
>
> If you don't care about whether T is an aggregate or not, what is
> stopping you from using the plain C++11 curly braces for
> initialization?
>
Because if T is not an aggregate, there is a clear ambiguity about what
exactly will be called. It could be a regular constructor; it could be an
initializer_list constructor. I don't know, and I have no way of telling
the system which I actually *want* to call.
Consider allocator_traits::construct. It cannot currently be used with
aggregates (without creating your own specialization of the traits class
for each aggregate); it will call this by default:
::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)
However, it could be extended to support initializing aggregates:
::new (static_cast<void*>(p)) T{std::forward<Args>(args)...}
Only now, we're not calling constructors anymore if T isn't an aggregate.
We might be interpreting what are supposed to be constructor parameters as
members of an initializer list. That's *bad*.
::new (static_cast<void*>(p)) T{c: std::forward<Args>(args)...}
With the new syntax, we are *guaranteed* to be calling a constructor or
performing aggregate initialization. That's good.
> Also, there's the fact that you can't use `()` syntax without a
> > typename:
> >
> > void Func(const std::vector &v) {...}
> >
> > Func( (42) ); //Does not work.
>
> This is a copy initialization context for 'v' and the constructor is
> explicit. I hope nobody actually wants this to invoke the constructor
> that takes a size parameter because that's the point of having
> explicit constructors.
>
OK, it does not work *for the wrong reasons*.
> Func( {42} ); //"works" but potentially does the wrong thing.
>
> By "potentially does the wrong thing" I guess you mean that the
> constructor taking a value for the size might be invoked by accident
> here. If so, You are wrong on this one because this constructor is
> explicit which is why it's not viable in this context.
>
It potentially does the wrong thing because the user has no way of
explicitly declaring what the right thing is. As you said, you "guessed"
that I meant that one might be invoked over another, but I explicitly left
out what the "right" thing was to make my point. Without the ability for
the user to say "I mean X", it is not clear what this code would do.
When the user wrote that braced-init-list, he had an idea in mind about how
it would be used to initialize the object. He either meant to call an
appropriate constructor, or he meant for it to be an initializer list. If
he meant to call a constructor, he should get a compiler error. If he meant
for it to be an initializer_list, he should get correct behavior.
Right now, we don't have a way to say *either* of these. We can only say
"try both, but start with initializer_lists".
> Func( {l: 42} ); //Does the right thing.
>
> We don't need the explicit 'l:' in this case to make the compiler
> prefer std::initializer_list constructors.
>
No, but we *do* need to be explicit in saying, "never call a
non-initializer_list constructor". Which is what the `l:` syntax says.
Thus, if `Func` took a `std::vector<SomeType>` instead of a
`std::vector<int>`, this would explicitly fail to compile by saying, "no
available initalizer_list constructor" or something to that effect. Rather
than the completely incorrect "attempt to call explicit constructor from
copy-list-initialization", since the programmer's intent is *not to call
that constructor at all*.
See the difference?
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_585_31164898.1359466353445
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Tuesday, January 29, 2013 5:11:18 AM UTC-8, Sebastian Gesemann w=
rote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;">On Tue, Jan 29, 2013 at 1=
:58 AM, Nicol Bolas <<a href=3D"javascript:" target=3D"_blank" gdf-obfus=
cated-mailto=3D"wBTN6YdqBAwJ">jmck...@gmail.com</a>> wrote:
<br>> On Monday, January 28, 2013 6:30:54 AM UTC-8, Sebastian Gesemann w=
rote:
<br>>>
<br>>> Nicol Bolas wrote:
<br>>> > [...]
<br>>>
<br>>> I'm sorry, I still don't get it. How can the use of
<br>>> T {l: ...}
<br>>> T {c: ...}
<br>>> instead of
<br>>> T {...}
<br>>> T (...)
<br>>> be considered more uniform? It does not appear to solve any pr=
oblem.
<br>>> What did I miss?
<br>>
<br>> You missed the fact that `T(...)` requires calling a constructor. =
`T{c:...}`
<br>> can use aggregate initialization if `T` is an aggregate.
<br>> The point is the ability to initialize aggregates or non-aggregate=
s in the
<br>> exact same way.
<br>
<br>If you don't care about whether T is an aggregate or not, what is
<br>stopping you from using the plain C++11 curly braces for
<br>initialization?<br></blockquote><div><br>Because if T is not an aggrega=
te, there is a clear ambiguity about what exactly will be called. It could =
be a regular constructor; it could be an initializer_list constructor. I do=
n't know, and I have no way of telling the system which I actually <i>want<=
/i> to call.<br><br>Consider allocator_traits::construct. It cannot current=
ly be used with aggregates (without creating your own specialization of the=
traits class for each aggregate); it will call this by default:<br><br><di=
v class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); bord=
er-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-=
wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint=
"><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span =
style=3D"color: #008;" class=3D"styled-by-prettify">new</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #008;" =
class=3D"styled-by-prettify">static_cast</span><span style=3D"color: #660;"=
class=3D"styled-by-prettify"><</span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">void</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">*>(</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify">p</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">))</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> T<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify">std</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify">forward</span><span style=3D"color:=
#660;" class=3D"styled-by-prettify"><</span><span style=3D"color: #606;=
" class=3D"styled-by-prettify">Args</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">>(</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify">args</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">)...)</span></div></code></div><br>However, it could be exten=
ded to support initializing aggregates:<br><br><div class=3D"prettyprint" s=
tyle=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 1=
87); border-style: solid; border-width: 1px; word-wrap: break-word;"><code =
class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #=
660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #008;" cl=
ass=3D"styled-by-prettify">new</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">(</span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">static_cast</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y"><</span><span style=3D"color: #008;" class=3D"styled-by-prettify">voi=
d</span><span style=3D"color: #660;" class=3D"styled-by-prettify">*>(</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify">p</span><span=
style=3D"color: #660;" class=3D"styled-by-prettify">))</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> T</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify">std</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">forward</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify"><</span><span style=3D"color: #606;" class=3D"styled-by-pre=
ttify">Args</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>>(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">args=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)...}</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span></di=
v></code></div><br>Only now, we're not calling constructors anymore if T is=
n't an aggregate. We might be interpreting what are supposed to be construc=
tor parameters as members of an initializer list. That's <i>bad</i>.<br><br=
><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); =
border-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; w=
ord-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyp=
rint"><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">new</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #008;=
" class=3D"styled-by-prettify">static_cast</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify"><</span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">void</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">*>(</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">p</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">))</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
T</span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify">c</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">:</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> std</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">forward</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify"><</span><span style=3D"color: #606;" class=3D"st=
yled-by-prettify">Args</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">>(</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify">args</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>)...}</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
</span></div></code></div><br>With the new syntax, we are <i>guaranteed</i>=
to be calling a constructor or performing aggregate initialization. That's=
good.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;ma=
rgin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
> Also, there's the fact that you can't use `()` syntax without a
<br>> typename:
<br>>
<br>> void Func(const std::vector &v) {...}
<br>>
<br>> Func( (42) ); //Does not work.
<br>
<br>This is a copy initialization context for 'v' and the constructor is
<br>explicit. I hope nobody actually wants this to invoke the constructor
<br>that takes a size parameter because that's the point of having
<br>explicit constructors.
<br></blockquote><div><br>OK, it does not work <i>for the wrong reasons</i>=
..<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-=
left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
> Func( {42} ); //"works" but potentially does the wrong thing.
<br>
<br>By "potentially does the wrong thing" I guess you mean that the
<br>constructor taking a value for the size might be invoked by accident
<br>here. If so, You are wrong on this one because this constructor is
<br>explicit which is why it's not viable in this context.<br></blockquote>=
<div><br>It potentially does the wrong thing because the user has no way of=
explicitly declaring what the right thing is. As you said, you "guessed" t=
hat I meant that one might be invoked over another, but I explicitly left o=
ut what the "right" thing was to make my point. Without the ability for the=
user to say "I mean X", it is not clear what this code would do.<br><br>Wh=
en the user wrote that braced-init-list, he had an idea in mind about=20
how it would be used to initialize the object. He either meant to call=20
an appropriate constructor, or he meant for it to be an initializer list. I=
f he meant to call a constructor, he should get a compiler error. If he mea=
nt for it to be an initializer_list, he should get correct behavior.<br><br=
>Right now, we don't have a way to say <i>either</i> of these. We can only =
say "try both, but start with initializer_lists".<br><br></div><blockquote =
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1p=
x #ccc solid;padding-left: 1ex;">
> Func( {l: 42} ); //Does the right thing.
<br>
<br>We don't need the explicit 'l:' in this case to make the compiler
<br>prefer std::initializer_list constructors.<br></blockquote><div><br>No,=
but we <i>do</i> need to be explicit in saying, "never call a non-initiali=
zer_list constructor". Which is what the `l:` syntax says. Thus, if `Func` =
took a `std::vector<SomeType>` instead of a `std::vector<int>`,=
this would explicitly fail to compile by saying, "no available initalizer_=
list constructor" or something to that effect. Rather than the completely i=
ncorrect "attempt to call explicit constructor from copy-list-initializatio=
n", since the programmer's intent is <i>not to call that constructor at all=
</i>.<br><br>See the difference?<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_585_31164898.1359466353445--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Tue, 29 Jan 2013 06:28:34 -0800 (PST)
Raw View
------=_Part_382_2144786.1359469714841
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, January 29, 2013 5:02:20 PM UTC+4, Nicol Bolas wrote:
>
>
> Uniform initialization syntax is not meant to be used only for "itemwise
> initialization".
>
So what? You are suggesting two different kinds of initialization, rather
than one uniform initialization syntax (as several people already noticed).
> It was, as stated in N2532, to be used in all cases of initialization. The
> goal here is to make it usable in all cases of initialization.
>
If that's the goal, it's not achieved.
> If you want to argue against this goal, take it up with Stroustrup.
>
I've tried. He is happy to live with the explanation that the only reason
why people don't like his beloved initialization syntax is that they just
don't like all new/unfamiliar features. He's VIP who doesn't want to
discuss technical details with plain people. This is my impression.
> It can't initialize aggregates.
>>>
>>
>> Actually it can initialize aggregates, but only with another instance:
>>
>> #include <iostream>
>> #include <string>
>>
>> struct A
>> {
>> std::string s;
>> int n;
>> };
>>
>> int main()
>> {
>> A a({"text", 1});
>> std::cout << a.s << "; " << a.n << std::endl;
>> }
>>
>> Here 'a' initialized with a temporary object, which is initialized with
>> the braced-init-list. It's possible to modify the rules so that
>> AggregateType({items...}) would be equivalent to AggregateType{items...}.
>>
>
> So you want to change the rules of how copy constructors for aggregates
> work
>
No, I would like to have a modifier ~, or +, or something else for a
braced-init-list such that
AggregateType a = ~ braced-init-list;
and
AggregateType a ( ~ braced-init-list );
would be equivalent to
AggregateType a = braced-init-list ;
while
NonAggregateType na1 = ~ braced-init-list;
and
NonAggregateType na2 ( ~ braced-init-list );
would consider only initializer-list constructors and the first parameter
of the selected constructor would be initialized with the braced-init-list.
struct A
{
std::string s;
int n;
};
int main()
{
A a1 = ~{"text", 1};
// equivalent to A a1 = {"text", 1};
A a2(~{"text", 1});
// equivalent to A a2 = {"text", 1};
std::vector<T> v = ~{20, T()};
// may create only two elements initialized with values 20 and T()
std::vector<T> v(~{20});
// may create only one element initialized with value 20
}
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_382_2144786.1359469714841
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Tuesday, January 29, 2013 5:02:20 PM UTC+4, Nicol Bolas wrote:<blockquot=
e class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: =
1px #ccc solid;padding-left: 1ex;"><div><br>Uniform initialization syntax i=
s not meant to be used only for "itemwise initialization".</div></blockquot=
e><div><br>So what? You are suggesting two different kinds of initializatio=
n, rather than one uniform initialization syntax (as several people already=
noticed).<br> </div><blockquote class=3D"gmail_quote" style=3D"margin=
: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div=
> It was, as stated in N2532, to be used in all cases of initialization. Th=
e goal here is to make it usable in all cases of initialization.<br></div><=
/blockquote><div><br>If that's the goal, it's not achieved.<br> </div>=
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bor=
der-left: 1px #ccc solid;padding-left: 1ex;"><div>If you want to argue agai=
nst this goal, take it up with Stroustrup.<br></div></blockquote><div><br>I=
've tried. He is happy to live with the explanation that the only reason wh=
y people don't like his beloved initialization syntax is that they just don=
't like all new/unfamiliar features. He's VIP who doesn't want to discuss t=
echnical details with plain people. This is my impression.<br> </div><=
blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bord=
er-left: 1px #ccc solid;padding-left: 1ex;"><div></div><blockquote class=3D=
"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc soli=
d;padding-left:1ex"><div></div><blockquote class=3D"gmail_quote" style=3D"m=
argin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div=
> It can't initialize aggregates.</div></blockquote><div><br>Actually it ca=
n initialize aggregates, but only with another instance:<br><br>  =
; #include <iostream><br> #include <string=
><br> <br> struct A<br> =
{<br> std::string s;<br> &nb=
sp; int n;<br> };<br> =
<br> int main()<br> {<br> &=
nbsp; A a({"text", 1});<br> =
std::cout << a.s << "; " << a.n =
<< std::endl;<br> }<br><br>Here 'a' initialized wit=
h a temporary object, which is initialized with the braced-init-list. It's =
possible to modify the rules so that AggregateType({items...}) would be equ=
ivalent to AggregateType{items...}.</div></blockquote><div><br>So you want =
to change the rules of how copy constructors for aggregates work</div></blo=
ckquote><div><br>No, I would like to have a modifier ~, or +, or something =
else for a braced-init-list such that<br><br> AggregateTy=
pe a =3D ~ braced-init-list;<br><br>and<br><br> Aggregate=
Type a ( ~ braced-init-list );<br><br>would be equivalent to<br><br> &=
nbsp; AggregateType a =3D braced-init-list ;<br><br>while<br><br>&nbs=
p; NonAggregateType na1 =3D ~ braced-init-list;<br><br>and<br><=
br> NonAggregateType na2 ( ~ braced-init-list );<br><br>w=
ould consider only initializer-list constructors and the first parameter of=
the selected constructor would be initialized with the braced-init-list.<b=
r><br> struct A<br> {<br> &n=
bsp; std::string s;<br> &nbs=
p; int n;<br> };<br><br> in=
t main()<br> {<br> &nb=
sp; A a1 =3D ~{"text", 1};<br> //=
equivalent to A a1 =3D {"text", 1};<br><br> &=
nbsp; A a2(~{"text", 1});<br> &nbs=
p; // equivalent to A a2 =3D {"text", 1};<br><br> &n=
bsp; std::vector<T> v =3D ~{20, T()};<br> &nbs=
p; // may create only two elements initialized with=
values 20 and T()<br><br> std::v=
ector<T> v(~{20});<br> // m=
ay create only one element initialized with value 20<br> =
}<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_382_2144786.1359469714841--
.
Author: Sebastian Gesemann <s.gesemann@gmail.com>
Date: Tue, 29 Jan 2013 15:41:29 +0100
Raw View
The only c++11 problem w.r.t. initialization I am aware of so far is
that when writing generic code like a container's emplace function or
std::make_shared/unique you have to decide what kind of initialization
syntax you should be using. Each choice has pros and cons.
This approach will fail to initialize aggregates:
template<class T, class...Args>
unique_ptr<T> make_unique(Args&&...args) {
... new T(forward<Args>(args)...) ...
}
This approach will make it impossible to invoke certain constructors:
template<class T, class...Args>
unique_ptr<T> make_unique(Args&&...args) {
... new T{forward<Args>(args)...} ...
}
Think of T=vector<int> where you want this vector to have a certain
initial size, not contain some specific value.
This is unsatisfying.
On Tue, Jan 29, 2013 at 2:32 PM, Nicol Bolas wrote:
> On Tuesday, January 29, 2013 5:11:18 AM UTC-8, Sebastian Gesemann wrote:
>> On Tue, Jan 29, 2013 at 1:58 AM, Nicol Bolas wrote:
>> > On Monday, January 28, 2013 6:30:54 AM UTC-8, Sebastian Gesemann wrote:
>> >>
>> >> Nicol Bolas wrote:
>> >> > [...]
>> >>
>> >> I'm sorry, I still don't get it. How can the use of
>> >> T {l: ...}
>> >> T {c: ...}
>> >> instead of
>> >> T {...}
>> >> T (...)
>> >> be considered more uniform? It does not appear to solve any problem.
>> >> What did I miss?
>> >
>> > You missed the fact that `T(...)` requires calling a constructor.
>> > `T{c:...}`
>> > can use aggregate initialization if `T` is an aggregate.
>> > The point is the ability to initialize aggregates or non-aggregates in
>> > the
>> > exact same way.
>>
>> If you don't care about whether T is an aggregate or not, what is
>> stopping you from using the plain C++11 curly braces for
>> initialization?
>
> Because if T is not an aggregate, there is a clear ambiguity about what
> exactly will be called. It could be a regular constructor; it could be an
> initializer_list constructor. I don't know, and I have no way of telling the
> system which I actually want to call.
I have trouble reading your mind on this one. What's the context? Do
you or don't you know what T? What kind of initialization (direct or
copy) are you thinking of?
> Consider allocator_traits::construct. It cannot currently be used with
> aggregates (without creating your own specialization of the traits class for
> each aggregate); it will call this by default:
>
> ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)
Right. This another example of a problem I acknowledge its existence
of. What I don't yet acknowledge is that this is a core language
problem. I also don't acknowledge that {c:...} or {l:...} fixes this
problem unless you want to offer two versions of construct. But
construct is not the only function like this. I mentioned earlier
make_shared, and the containers' emplace functions. Having to write
two versions of these functions is a major PITA.
I would much rather have a solution that does not require offering
multiple overloads of these functions. I'd much rather have overload
resolution rules take care of picking the right constructor. And I'd
much rather have perfect forwarding be able to pass such ambiguity
resolving things.
Here's a completly different idea for a solution: Disable
std::list_initialiter list constructor consideration by using a
special first element of a {}-list that will then be discarded during
overload resolution for picking the right constructor.
vector<int> v {nolist,42};
It could be made to work even for the forwarding case so that we don't
have to specify so many additional functions:
template<class T, class...Args>
unique_ptr<T> make_unique(Args&&...args)
{
return unique_ptr<T>(new T{forward<Args>(args)...});
}
int main() {
auto up = make_unique<vector<int>>(nolist,42);
// Deduction of Args: some unspecified special type, int
}
In my opinion, having different calling syntaxes () and {} modify
overload resolution is a bad idea. Overload resolution should just be
dependent on the parameter types so that one can write agnostic
forwarders that don't need to add special casing w.r.t. () and {}
> ::new (static_cast<void*>(p)) T{c: std::forward<Args>(args)...}
>
> With the new syntax, we are guaranteed to be calling a constructor or
> performing aggregate initialization. That's good.
And what about the case where you actually want the initialier_list
constructor? Do you plan to offer two construct functions? I hope not.
>> > Func( {42} ); //"works" but potentially does the wrong thing.
>>
>> By "potentially does the wrong thing" I guess you mean that the
>> constructor taking a value for the size might be invoked by accident
>> here. If so, You are wrong on this one because this constructor is
>> explicit which is why it's not viable in this context.
>
> It potentially does the wrong thing because the user has no way of
> explicitly declaring what the right thing is. As you said, you "guessed"
> that I meant that one might be invoked over another, but I explicitly left
> out what the "right" thing was to make my point. Without the ability for the
> user to say "I mean X", it is not clear what this code would do.
>
> When the user wrote that braced-init-list, he had an idea in mind about how
> it would be used to initialize the object. He either meant to call an
> appropriate constructor, or he meant for it to be an initializer list. If he
> meant to call a constructor, he should get a compiler error. If he meant for
> it to be an initializer_list, he should get correct behavior.
It's hard to comment on this. It was an artifical example with an
unknown signature of Func. If Func took a vector<int> I would say the
code looks fine.
The general rule should be: Don't overload too eagerly. It has been
mentioned before and I would like to repeat it again: It can be argued
that the overloading of vector's constructor is unfortunate. What I
don't like about your proposal is that you invent a new way of
controlling overload resolution. IMHO, overload resolution should just
depend on the parameters which should all be forwardable.
> Right now, we don't have a way to say either of these. We can only say "try
> both, but start with initializer_lists".
>
>> > Func( {l: 42} ); //Does the right thing.
>>
>> We don't need the explicit 'l:' in this case to make the compiler
>> prefer std::initializer_list constructors.
>
> No, but we do need to be explicit in saying, "never call a
> non-initializer_list constructor". Which is what the `l:` syntax says. Thus,
> if `Func` took a `std::vector<SomeType>` instead of a `std::vector<int>`,
> this would explicitly fail to compile by saying, "no available
> initalizer_list constructor" or something to that effect. Rather than the
> completely incorrect "attempt to call explicit constructor from
> copy-list-initialization", since the programmer's intent is not to call that
> constructor at all.
>
> See the difference?
Right. Then you probably my idea from above to include a counterpart
of "nolist". ;-)
Anyways, tbh, it doesn't change how I feel about your proposal. It
does not seem to fit well into the rest of c++ and the need to special
case functions like make_shared or construct is bad.
Cheers!
SG
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Tue, 29 Jan 2013 07:13:49 -0800 (PST)
Raw View
------=_Part_518_17884321.1359472429448
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, January 29, 2013 6:41:29 PM UTC+4, Sebastian Gesemann wrote:
>
>
> Here's a completly different idea for a solution: Disable
> std::list_initialiter list constructor consideration by using a
> special first element of a {}-list that will then be discarded during
> overload resolution for picking the right constructor.
>
> vector<int> v {nolist,42};
>
> It could be made to work even for the forwarding case so that we don't
> have to specify so many additional functions:
>
> template<class T, class...Args>
> unique_ptr<T> make_unique(Args&&...args)
> {
> return unique_ptr<T>(new T{forward<Args>(args)...});
> }
>
What would you suggest to do with existing templates, such as emplace and
make_shared?
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_518_17884321.1359472429448
Content-Type: text/html; charset=ISO-8859-1
On Tuesday, January 29, 2013 6:41:29 PM UTC+4, Sebastian Gesemann wrote:<blockquote class="gmail_quote" style="margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>Here's a completly different idea for a solution: Disable
<br>std::list_initialiter list constructor consideration by using a
<br>special first element of a {}-list that will then be discarded during
<br>overload resolution for picking the right constructor.
<br>
<br> vector<int> v {nolist,42};
<br>
<br>It could be made to work even for the forwarding case so that we don't
<br>have to specify so many additional functions:
<br>
<br> template<class T, class...Args>
<br> unique_ptr<T> make_unique(Args&&...args)
<br> {
<br> return unique_ptr<T>(new T{forward<Args>(args)...});
<br> }
<br></blockquote><div><br>What would you suggest to do with existing templates, such as emplace and make_shared?<br></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href="http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en">http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en</a>.<br />
<br />
<br />
------=_Part_518_17884321.1359472429448--
.
Author: vattilah-groups@yahoo.co.uk
Date: Tue, 29 Jan 2013 10:04:51 -0800 (PST)
Raw View
------=_Part_2064_17085356.1359482691969
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, 29 January 2013 14:41:29 UTC, Sebastian Gesemann wrote:
> Anyways, tbh, it doesn't change how I feel about your proposal. It
> does not seem to fit well into the rest of c++ and the need to special
> case functions like make_shared or construct is bad.
On a related note, I just browsed the C++ Standard Library Active Issues
List (N3516) and noticed issue 2089, "std::allocator::construct should use
uniform initialization".
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2089
It proposes to solve the problem in emplace_back (currently not allowing
aggregate-initialization and list-initialization) by meta-programming using
type traits. These programming techniques are now part of a
well-established toolbox for controlling overload resolution, and the mood
may very well be that this is sufficient to deal with the initialization
quirks in the language as well.
> The general rule should be: Don't overload too eagerly.
Yes, when it comes to the demonstrated ambiguities in std::vector <int>,
the fact remains that no well-designed class interface should introduce
these ambiguities in the first place. So this design problem may end up
being dealt with by coding standards, i.e. similar to the current "always
include a virtual destructor in your polymorphic base class", we will have
"always do this-that-and-the-other if you include an il-constructor in your
class".
Regards,
Vidar Hasfjord
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_2064_17085356.1359482691969
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div style=3D"margin-bottom: 0cm;" class=3D"western">On Tuesday, 29 January
2013 14:41:29 UTC, Sebastian Gesemann wrote:</div><div style=3D"margin-bott=
om: 0cm;" class=3D"western">> Anyways, tbh, it
doesn't change how I feel about your proposal. It</div><div style=3D"margin=
-bottom: 0cm;" class=3D"western">> does not seem to
fit well into the rest of c++ and the need to special</div><div style=3D"ma=
rgin-bottom: 0cm;" class=3D"western">> case functions
like make_shared or construct is bad.</div><div style=3D"margin-bottom: 0cm=
;" class=3D"western"> </div><div style=3D"margin-bottom: 0cm;" class=
=3D"western">On a related note, I
just browsed the C++ Standard Library Active Issues List (N3516) and
noticed issue 2089, "std::allocator::construct should use
uniform initialization".</div><div style=3D"margin-bottom: 0cm;" class=3D"w=
estern"> </div><div style=3D"margin-bottom: 0cm;" class=3D"western"><a=
href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2089">=
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2089</a></div><=
div style=3D"margin-bottom: 0cm;" class=3D"western"> </div><div style=
=3D"margin-bottom: 0cm;" class=3D"western">It proposes to solve
the problem in emplace_back (currently not allowing
aggregate-initialization and list-initialization) by meta-programming
using type traits. These programming techniques are now part of a
well-established toolbox for controlling overload resolution,
and the mood may very well be that this is sufficient to deal with
the initialization quirks in the language as well.</div><div style=3D"margi=
n-bottom: 0cm;" class=3D"western"> </div><div style=3D"margin-bottom: =
0cm;" class=3D"western">> The general rule
should be: Don't overload too eagerly.</div><div style=3D"margin-bottom: 0c=
m;" class=3D"western"> </div><div style=3D"margin-bottom: 0cm;" class=
=3D"western">Yes, when it comes to
the demonstrated ambiguities in std::vector <int>, the fact
remains that no well-designed class interface should introduce these
ambiguities in the first place. So this design problem may end up
being dealt with by coding standards, i.e. similar to the current
"always include a virtual destructor in your polymorphic base
class", we will have "always do this-that-and-the-other if
you include an il-constructor in your class".</div><div style=3D"margin-bot=
tom: 0cm;" class=3D"western"> </div><div style=3D"margin-bottom: 0cm;"=
class=3D"western">Regards,</div><div style=3D"margin-bottom: 0cm;" class=
=3D"western">Vidar Hasfjord</div><div style=3D"margin-bottom: 0cm;" class=
=3D"western"> </div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_2064_17085356.1359482691969--
.
Author: vattilah-groups@yahoo.co.uk
Date: Tue, 29 Jan 2013 11:07:54 -0800 (PST)
Raw View
------=_Part_1938_32577031.1359486474913
Content-Type: text/plain; charset=ISO-8859-1
On Monday, 28 January 2013 12:19:30 UTC, Nikolay Ivchenkov wrote:
>
> vector <int> a = {42}; // OK: Pass single element (copy-initialization
>> excludes explict constructors).
>
>
> 1) Explicit constructors are still considered here.
>
Are you sure? Isn't this a copy-initialization context? At least, GCC 4.5.1
does not consider the explicit constructor here:
http://ideone.com/P5fQn1
> 2) In the following case
>
> vector <int> a = {42, 1};
>
> there are two viable converting constructors.
>
True, since this does not involve explicit constructors, you cannot use
copy-initialization to disambiguate.
Regards,
Vidar Hasfjord
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_1938_32577031.1359486474913
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Monday, 28 January 2013 12:19:30 UTC, Nikolay Ivchenkov wrote:<blockquo=
te style=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color=
: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid;" cl=
ass=3D"gmail_quote"><blockquote style=3D"margin: 0px 0px 0px 0.8ex; padding=
-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width: 1px; =
border-left-style: solid;" class=3D"gmail_quote">vector <int> a =3D {=
42}; // OK: Pass single element (copy-initialization excludes explict const=
ructors).</blockquote><div><br>1) Explicit constructors are still considere=
d here.</div></blockquote><div> </div><div>Are you sure? Isn't this a =
copy-initialization context? At least, GCC 4.5.1 does not consider the expl=
icit constructor here:</div><div> </div><div><a href=3D"http://ideone.=
com/P5fQn1">http://ideone.com/P5fQn1</a></div><div> </div><blockquote =
style=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: r=
gb(204, 204, 204); border-left-width: 1px; border-left-style: solid;" class=
=3D"gmail_quote"><div>2) In the following case<br><br> ve=
ctor <int> a =3D {42, 1};<br><br>there are two viable converting cons=
tructors. </div></blockquote><div> </div><div>True, since th=
is does not involve explicit constructors, you cannot use copy-initializati=
on to disambiguate. </div><div> </div><div>Regards,</div><div>Vid=
ar Hasfjord</div><div> </div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_1938_32577031.1359486474913--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Tue, 29 Jan 2013 11:40:03 -0800 (PST)
Raw View
------=_Part_297_15735750.1359488403284
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, January 29, 2013 10:04:51 PM UTC+4, vattila...@yahoo.co.uk
wrote:
>
>
> > The general rule should be: Don't overload too eagerly.
>
> Yes, when it comes to the demonstrated ambiguities in std::vector <int>,
> the fact remains that no well-designed class interface should introduce
> these ambiguities in the first place.
>
Such overload set might work perfectly well with a different model of
initialization. Currently we can't simply use
auto f = &std::vector<int>::push_back
at least because std::vector<int>::push_back is overloaded, so we should
consider this as an example of bad library design too, huh? I'd rather
prefer to think that & is too weak and its use should be limited.
So this design problem may end up being dealt with by coding standards,
> i.e. similar to the current "always include a virtual destructor in your
> polymorphic base class", we will have "always do this-that-and-the-other if
> you include an il-constructor in your class".
>
or: "restrict use of broken things like list-initialization" :-)
On Tuesday, January 29, 2013 11:07:54 PM UTC+4, vattila...@yahoo.co.uk
wrote:
>
> On Monday, 28 January 2013 12:19:30 UTC, Nikolay Ivchenkov wrote:
>>
>> vector <int> a = {42}; // OK: Pass single element (copy-initialization
>>> excludes explict constructors).
>>
>>
>> 1) Explicit constructors are still considered here.
>>
>
> Are you sure? Isn't this a copy-initialization context? At least, GCC
> 4.5.1 does not consider the explicit constructor here:
>
> http://ideone.com/P5fQn1
>
I'm sure, and the diagnostic message clearly says that the explicit
constructor is selected.
See also http://liveworkspace.org/code/21QHT3$0
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_297_15735750.1359488403284
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Tuesday, January 29, 2013 10:04:51 PM UTC+4, vattila...@yahoo.co.uk wrot=
e:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;"><br><div style=3D"margin-bot=
tom:0cm">> The general rule
should be: Don't overload too eagerly.</div><div style=3D"margin-bottom:0cm=
"> </div><div style=3D"margin-bottom:0cm">Yes, when it comes to
the demonstrated ambiguities in std::vector <int>, the fact
remains that no well-designed class interface should introduce these
ambiguities in the first place.</div></blockquote><div><br>Such overload se=
t might work perfectly well with a different model of initialization. Curre=
ntly we can't simply use<br><br> auto f =3D &std::vec=
tor<int>::push_back<br><br>at least because std::vector<int>::p=
ush_back is overloaded, so we should consider this as an example of bad lib=
rary design too, huh? I'd rather prefer to think that & is too weak and=
its use should be limited.<br><br></div><blockquote class=3D"gmail_quote" =
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-l=
eft: 1ex;"><div style=3D"margin-bottom:0cm"> So this design problem may end=
up
being dealt with by coding standards, i.e. similar to the current
"always include a virtual destructor in your polymorphic base
class", we will have "always do this-that-and-the-other if
you include an il-constructor in your class".</div></blockquote><div><br>or=
: "restrict use of broken things like list-initialization" :-)<br><br>On Tu=
esday, January 29, 2013 11:07:54 PM UTC+4, vattila...@yahoo.co.uk wrote:<bl=
ockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border=
-left: 1px #ccc solid;padding-left: 1ex;">On Monday, 28 January 2013 12:19:=
30 UTC, Nikolay Ivchenkov wrote:<blockquote style=3D"margin:0px 0px 0px 0.=
8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1=
px;border-left-style:solid" class=3D"gmail_quote"><blockquote style=3D"marg=
in:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);bo=
rder-left-width:1px;border-left-style:solid" class=3D"gmail_quote">vector &=
lt;int> a =3D {42}; // OK: Pass single element (copy-initialization excl=
udes explict constructors).</blockquote><div><br>1) Explicit constructors a=
re still considered here.</div></blockquote><div> </div><div>Are you s=
ure? Isn't this a copy-initialization context? At least, GCC 4.5.1 does not=
consider the explicit constructor here:</div><div> </div><div><a href=
=3D"http://ideone.com/P5fQn1" target=3D"_blank">http://ideone.com/P5fQn1</a=
></div></blockquote><div><br>I'm sure, and the diagnostic message clearly s=
ays that the explicit constructor is selected.<br>See also http://liveworks=
pace.org/code/21QHT3$0</div> </div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_297_15735750.1359488403284--
.
Author: vattilah-groups@yahoo.co.uk
Date: Tue, 29 Jan 2013 13:24:09 -0800 (PST)
Raw View
------=_Part_802_33012184.1359494649610
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, 29 January 2013 19:40:03 UTC, Nikolay Ivchenkov wrote:
>
> I'm sure, and the diagnostic message clearly says that the explicit
> constructor is selected.
>
Thanks, I finally get your point. To recap and correct myself:
vector <int> v = {42};
If the il-preference rule was revoked, this would not work to disambiguate
in favour of the il-constructor. The fact that the size-constructor is
explicit doesn't exclude it from the overload set. That would need a
special rule that disambiguated in favour of the il-constructor in specific
contexts, which would just complicate things.
Which leaves us with the mouthful option:
vector <int> a (initializer_list <int> {42}); // OK: Pass single element.
Regards,
Vidar Hasfjord
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_802_33012184.1359494649610
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Tuesday, 29 January 2013 19:40:03 UTC, Nikolay Ivchenkov wrote:<blockqu=
ote style=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-colo=
r: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid;" c=
lass=3D"gmail_quote"><div><div>I'm sure, and the diagnostic message clearly=
says that the explicit constructor is selected.</div></div></blockquote><d=
iv> </div><div>Thanks, I finally get your point. To recap and correct =
myself:</div><div> </div><div>vector <int> v =3D {42};</div><div=
> </div><div>If the il-preference rule was revoked, this would no=
t work to disambiguate in favour of the il-constructor. The fact that&=
nbsp;the size-constructor is explicit doesn't exclude it from the over=
load set. That would need a special rule that disambiguated in favour =
of the il-constructor in specific contexts, which would just complicate thi=
ngs.</div><div> </div><div>Which leaves us with the mouthful option:</=
div><div> </div><div>vector <int> a (initializer_list <int>=
; {42}); // OK: Pass single element.</div><div> </div><div>Regards,</d=
iv><div>Vidar Hasfjord</div><div> </div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_802_33012184.1359494649610--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 29 Jan 2013 19:05:50 -0800 (PST)
Raw View
------=_Part_1183_2856449.1359515150536
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, January 29, 2013 6:28:34 AM UTC-8, Nikolay Ivchenkov wrote:
>
> On Tuesday, January 29, 2013 5:02:20 PM UTC+4, Nicol Bolas wrote:
>>
>>
>> Uniform initialization syntax is not meant to be used only for "itemwise
>> initialization".
>>
>
> So what? You are suggesting two different kinds of initialization, rather
> than one uniform initialization syntax (as several people already noticed).
>
I'm suggesting two slight variations of initialization syntax, so that the
user can express what they're getting. The only difference is which
constructors are considered; all of the other aspects of initialization
(initializing aggregates, figuring out what type to use, etc) remain the
same. In short, 90% of the text around such braced-init-lists in the
standard will be identical; all that changes is the part of 13.3.1.7 that
says which constructors are considered.
That's hardly "two different kinds of initialization."
As stated in the proposal, the ideal solution would have been to make {}
never translate into initializer list constructors to begin with. So if you
wanted to make a vector<int> of one element, you use {{42}}. But since that
ship has sailed, this is the best solution left: allow the user to pick one
or the other on a case-by-case basis.
We do the best with what we have.
It was, as stated in N2532, to be used in all cases of initialization. The
>> goal here is to make it usable in all cases of initialization.
>>
>
> If that's the goal, it's not achieved.
>
>
>> If you want to argue against this goal, take it up with Stroustrup.
>>
>
> I've tried. He is happy to live with the explanation that the only reason
> why people don't like his beloved initialization syntax is that they just
> don't like all new/unfamiliar features. He's VIP who doesn't want to
> discuss technical details with plain people. This is my impression.
>
>
>> It can't initialize aggregates.
>>>>
>>>
>>> Actually it can initialize aggregates, but only with another instance:
>>>
>>> #include <iostream>
>>> #include <string>
>>>
>>> struct A
>>> {
>>> std::string s;
>>> int n;
>>> };
>>>
>>> int main()
>>> {
>>> A a({"text", 1});
>>> std::cout << a.s << "; " << a.n << std::endl;
>>> }
>>>
>>> Here 'a' initialized with a temporary object, which is initialized with
>>> the braced-init-list. It's possible to modify the rules so that
>>> AggregateType({items...}) would be equivalent to AggregateType{items...}.
>>>
>>
>> So you want to change the rules of how copy constructors for aggregates
>> work
>>
>
> No, I would like to have a modifier ~, or +, or something else for a
> braced-init-list such that
>
> AggregateType a = ~ braced-init-list;
>
> and
>
> AggregateType a ( ~ braced-init-list );
>
> would be equivalent to
>
> AggregateType a = braced-init-list ;
>
> while
>
> NonAggregateType na1 = ~ braced-init-list;
>
> and
>
> NonAggregateType na2 ( ~ braced-init-list );
>
> would consider only initializer-list constructors and the first parameter
> of the selected constructor would be initialized with the braced-init-list.
>
That's what {l:} does.
Furthermore, {l:} is not enough, because there's no way to have similar
behavior but only consider regular constructors. That's what {c:} is for.
Of course, you don't want that because you don't want uniform
initialization syntax at all. You don't *want* users to use {} syntax
everywhere to initialize things. I understand that, but since this proposal
is all about making that possible your idea isn't helpful.
Personally, I've never understood this notion that aggregate initialization
is in any way like initializer_list initialization. It's far more like
constructor syntax than initializer_lists, since aggregates don't have to
contain the same types. That's why {} should only have considered regular
constructors to begin with, forcing the use of {{}} for initializer_list
initialization.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_1183_2856449.1359515150536
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Tuesday, January 29, 2013 6:28:34 AM UTC-8, Nikolay Ivchenkov wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">On Tuesday, January 29, 20=
13 5:02:20 PM UTC+4, Nicol Bolas wrote:<blockquote class=3D"gmail_quote" st=
yle=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1=
ex"><div><br>Uniform initialization syntax is not meant to be used only for=
"itemwise initialization".</div></blockquote><div><br>So what? You are sug=
gesting two different kinds of initialization, rather than one uniform init=
ialization syntax (as several people already noticed).<br></div></blockquot=
e><div><br>I'm suggesting two slight variations of initialization syntax, s=
o that the user can express what they're getting. The only difference is wh=
ich constructors are considered; all of the other aspects of initialization=
(initializing aggregates, figuring out what type to use, etc) remain the s=
ame. In short, 90% of the text around such braced-init-lists in the standar=
d will be identical; all that changes is the part of 13.3.1.7 that says whi=
ch constructors are considered.<br><br>That's hardly "two different kinds o=
f initialization."<br><br>As stated in the proposal, the ideal solution wou=
ld have been to make {} never translate into initializer list constructors =
to begin with. So if you wanted to make a vector<int> of one element,=
you use {{42}}. But since that ship has sailed, this is the best solution =
left: allow the user to pick one or the other on a case-by-case basis.<br><=
br>We do the best with what we have.<br><br></div><blockquote class=3D"gmai=
l_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;=
padding-left: 1ex;"><div></div><blockquote class=3D"gmail_quote" style=3D"m=
argin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div=
> It was, as stated in N2532, to be used in all cases of initialization. Th=
e goal here is to make it usable in all cases of initialization.<br></div><=
/blockquote><div><br>If that's the goal, it's not achieved.<br> </div>=
<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;borde=
r-left:1px #ccc solid;padding-left:1ex"><div>If you want to argue against t=
his goal, take it up with Stroustrup.<br></div></blockquote><div><br>I've t=
ried. He is happy to live with the explanation that the only reason why peo=
ple don't like his beloved initialization syntax is that they just don't li=
ke all new/unfamiliar features. He's VIP who doesn't want to discuss techni=
cal details with plain people. This is my impression.<br></div></blockquote=
><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bo=
rder-left: 1px #ccc solid;padding-left: 1ex;"><div> </div><blockquote =
class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #=
ccc solid;padding-left:1ex"><div></div><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1=
ex"><div></div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-l=
eft:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div> It can't initi=
alize aggregates.</div></blockquote><div><br>Actually it can initialize agg=
regates, but only with another instance:<br><br> #include=
<iostream><br> #include <string><br> &n=
bsp; <br> struct A<br> {<br>  =
; std::string s;<br> &=
nbsp; int n;<br> };<br> <br> =
; int main()<br> {<br>  =
; A a({"text", 1});<br> &nbs=
p; std::cout << a.s << "; " << a.n << std::en=
dl;<br> }<br><br>Here 'a' initialized with a temporary ob=
ject, which is initialized with the braced-init-list. It's possible to modi=
fy the rules so that AggregateType({items...}) would be equivalent to Aggre=
gateType{items...}.</div></blockquote><div><br>So you want to change the ru=
les of how copy constructors for aggregates work</div></blockquote><div><br=
>No, I would like to have a modifier ~, or +, or something else for a brace=
d-init-list such that<br><br> AggregateType a =3D ~ brace=
d-init-list;<br><br>and<br><br> AggregateType a ( ~ brace=
d-init-list );<br><br>would be equivalent to<br><br> Aggr=
egateType a =3D braced-init-list ;<br><br>while<br><br> N=
onAggregateType na1 =3D ~ braced-init-list;<br><br>and<br><br> &=
nbsp; NonAggregateType na2 ( ~ braced-init-list );<br><br>would consider on=
ly initializer-list constructors and the first parameter of the selected co=
nstructor would be initialized with the braced-init-list.<br></div></blockq=
uote><div><br>That's what {l:} does.<br><br>Furthermore, {l:} is not enough=
, because there's no way to have similar behavior but only consider regular=
constructors. That's what {c:} is for.<br><br>Of course, you don't want th=
at because you don't want uniform initialization syntax at all. You don't <=
i>want</i> users to use {} syntax everywhere to initialize things. I unders=
tand that, but since this proposal is all about making that possible your i=
dea isn't helpful.<br><br>Personally, I've never understood this notion tha=
t aggregate initialization is in any way like initializer_list initializati=
on. It's far more like constructor syntax than initializer_lists, since agg=
regates don't have to contain the same types. That's why {} should only hav=
e considered regular constructors to begin with, forcing the use of {{}} fo=
r initializer_list initialization.</div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_1183_2856449.1359515150536--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 29 Jan 2013 19:17:55 -0800 (PST)
Raw View
------=_Part_1700_11115284.1359515875922
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, January 29, 2013 10:04:51 AM UTC-8, vattila...@yahoo.co.uk
wrote:
>
> On Tuesday, 29 January 2013 14:41:29 UTC, Sebastian Gesemann wrote:
> > Anyways, tbh, it doesn't change how I feel about your proposal. It
> > does not seem to fit well into the rest of c++ and the need to special
> > case functions like make_shared or construct is bad.
>
> On a related note, I just browsed the C++ Standard Library Active Issues
> List (N3516) and noticed issue 2089, "std::allocator::construct should use
> uniform initialization".
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2089
>
> It proposes to solve the problem in emplace_back (currently not allowing
> aggregate-initialization and list-initialization) by meta-programming using
> type traits. These programming techniques are now part of a
> well-established toolbox for controlling overload resolution, and the mood
> may very well be that this is sufficient to deal with the initialization
> quirks in the language as well.
>
It's interesting that the proposed language is the exact opposite of how {}
works now. It picks constructors *first*, then initializer_list
constructors if no matching constructor is found.
Of course, this just transplants one problem with another: with this, the
regular constructors are shadowing possible initializer_list constructors.
However, at least this way, the user does have the ability to use an
initializer_list constructor by passing an initializer_list when they mean
to use one. It may be bulkier, but it does *work*.
Granted, there would be no need for this deduction stuff if they had {c:},
which would be effectively equivalent (save never using initializer_list
constructors without explicitly specifying it, but I would consider that an
improvement)
> The general rule should be: Don't overload too eagerly.
>
> Yes, when it comes to the demonstrated ambiguities in std::vector <int>,
> the fact remains that no well-designed class interface should introduce
> these ambiguities in the first place. So this design problem may end up
> being dealt with by coding standards, i.e. similar to the current "always
> include a virtual destructor in your polymorphic base class", we will have
> "always do this-that-and-the-other if you include an il-constructor in your
> class".
>
Or, you know, we could just *fix the problem.* The problem is only
ambiguous because the user cannot accurately express what they want.
Instead of forcing every writer of a class to prevent the ambiguity, let's
just allow programmers to say what it is that they actually want.
I don't understand this resistance to such an obvious language fix. The
language doesn't let us say what we really want to do; the obvious solution
is to allow us to say what we really want to do. This isn't rocket science
here.
Thinking like you're doing is what gives us nightmare library features like
`std::enable_if` and other similar metaprogramming garbage. It's always
easier to just make everyone else do more work than to fix the problem
right. Yes, they work, but they're horrible to read and painful to use.
We as C++ programmers need to stop relying on these quick-fix solutions.
Isn't that why the C++ committee is moving to a faster release cycle? So
that we can get real fixes for real problems the right way, in a timely
manor?
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_1700_11115284.1359515875922
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Tuesday, January 29, 2013 10:04:51 AM UTC-8, vattila...@yahoo.co=
..uk wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:=
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<div style=3D"margin-bottom:0cm">On Tuesday, 29 January
2013 14:41:29 UTC, Sebastian Gesemann wrote:</div><div style=3D"margin-bott=
om:0cm">> Anyways, tbh, it
doesn't change how I feel about your proposal. It</div><div style=3D"margin=
-bottom:0cm">> does not seem to
fit well into the rest of c++ and the need to special</div><div style=3D"ma=
rgin-bottom:0cm">> case functions
like make_shared or construct is bad.</div><div style=3D"margin-bottom:0cm"=
> </div><div style=3D"margin-bottom:0cm">On a related note, I
just browsed the C++ Standard Library Active Issues List (N3516) and
noticed issue 2089, "std::allocator::construct should use
uniform initialization".</div><div style=3D"margin-bottom:0cm"> </div>=
<div style=3D"margin-bottom:0cm"><a href=3D"http://www.open-std.org/jtc1/sc=
22/wg21/docs/lwg-active.html#2089" target=3D"_blank">http://www.open-std.or=
g/jtc1/<wbr>sc22/wg21/docs/lwg-active.<wbr>html#2089</a></div><div style=3D=
"margin-bottom:0cm"> </div><div style=3D"margin-bottom:0cm">It propose=
s to solve
the problem in emplace_back (currently not allowing
aggregate-initialization and list-initialization) by meta-programming
using type traits. These programming techniques are now part of a
well-established toolbox for controlling overload resolution,
and the mood may very well be that this is sufficient to deal with
the initialization quirks in the language as well.</div></blockquote><div><=
br>It's interesting that the proposed language is the exact opposite of how=
{} works now. It picks constructors <i>first</i>, then initializer_list co=
nstructors if no matching constructor is found.<br><br>Of course, this just=
transplants one problem with another: with this, the regular constructors =
are shadowing possible initializer_list constructors. However, at least thi=
s way, the user does have the ability to use an initializer_list constructo=
r by passing an initializer_list when they mean to use one. It may be bulki=
er, but it does <i>work</i>.<br><br>Granted, there would be no need for thi=
s deduction stuff if they had {c:}, which would be effectively equivalent (=
save never using initializer_list constructors without explicitly specifyin=
g it, but I would consider that an improvement)<br><br></div><blockquote cl=
ass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px =
#ccc solid;padding-left: 1ex;"><div style=3D"margin-bottom:0cm"></div><div =
style=3D"margin-bottom:0cm">> The general rule
should be: Don't overload too eagerly.</div><div style=3D"margin-bottom:0cm=
"> </div><div style=3D"margin-bottom:0cm">Yes, when it comes to
the demonstrated ambiguities in std::vector <int>, the fact
remains that no well-designed class interface should introduce these
ambiguities in the first place. So this design problem may end up
being dealt with by coding standards, i.e. similar to the current
"always include a virtual destructor in your polymorphic base
class", we will have "always do this-that-and-the-other if
you include an il-constructor in your class".</div></blockquote><div><br>Or=
, you know, we could just <i>fix the problem.</i> The problem is only ambig=
uous because the user cannot accurately express what they want. Instead of =
forcing every writer of a class to prevent the ambiguity, let's just allow =
programmers to say what it is that they actually want.<br><br>I don't under=
stand this resistance to such an obvious language fix. The language doesn't=
let us say what we really want to do; the obvious solution is to allow us =
to say what we really want to do. This isn't rocket science here.<br><br>Th=
inking like you're doing is what gives us nightmare library features like `=
std::enable_if` and other similar metaprogramming garbage. It's always easi=
er to just make everyone else do more work than to fix the problem right. Y=
es, they work, but they're horrible to read and painful to use.<br><br>We a=
s C++ programmers need to stop relying on these quick-fix solutions. Isn't =
that why the C++ committee is moving to a faster release cycle? So that we =
can get real fixes for real problems the right way, in a timely manor?<br><=
/div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_1700_11115284.1359515875922--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 29 Jan 2013 19:25:53 -0800 (PST)
Raw View
------=_Part_1022_6791960.1359516353735
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, January 29, 2013 7:17:55 PM UTC-8, Nicol Bolas wrote:
>
>
> > The general rule should be: Don't overload too eagerly.
>>
>> Yes, when it comes to the demonstrated ambiguities in std::vector <int>,
>> the fact remains that no well-designed class interface should introduce
>> these ambiguities in the first place. So this design problem may end up
>> being dealt with by coding standards, i.e. similar to the current "always
>> include a virtual destructor in your polymorphic base class", we will have
>> "always do this-that-and-the-other if you include an il-constructor in your
>> class".
>>
>
> Or, you know, we could just *fix the problem.* The problem is only
> ambiguous because the user cannot accurately express what they want.
> Instead of forcing every writer of a class to prevent the ambiguity, let's
> just allow programmers to say what it is that they actually want.
>
> I don't understand this resistance to such an obvious language fix. The
> language doesn't let us say what we really want to do; the obvious solution
> is to allow us to say what we really want to do. This isn't rocket science
> here.
>
> Thinking like you're doing is what gives us nightmare library features
> like `std::enable_if` and other similar metaprogramming garbage. It's
> always easier to just make everyone else do more work than to fix the
> problem right. Yes, they work, but they're horrible to read and painful to
> use.
>
> We as C++ programmers need to stop relying on these quick-fix solutions.
> Isn't that why the C++ committee is moving to a faster release cycle? So
> that we can get real fixes for real problems the right way, in a timely
> manor?
>
Indeed, arguing against having a fix is like saying that we shouldn't allow
this to work:
void Func(int i);
void Func(float f);
Func(1.0); //Ambiguous call
Func((float)1.0); //Ambiguity resolved
My proposal is conceptually no different than this.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_1022_6791960.1359516353735
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Tuesday, January 29, 2013 7:17:55 PM UTC-8, Nicol Bolas wrote:<b=
lockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;borde=
r-left: 1px #ccc solid;padding-left: 1ex;"><br><div></div><blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><div style=3D"margin-bottom:0cm"></div><div style=3D=
"margin-bottom:0cm">> The general rule
should be: Don't overload too eagerly.</div><div style=3D"margin-bottom:0cm=
"> </div><div style=3D"margin-bottom:0cm">Yes, when it comes to
the demonstrated ambiguities in std::vector <int>, the fact
remains that no well-designed class interface should introduce these
ambiguities in the first place. So this design problem may end up
being dealt with by coding standards, i.e. similar to the current
"always include a virtual destructor in your polymorphic base
class", we will have "always do this-that-and-the-other if
you include an il-constructor in your class".</div></blockquote><div><br>Or=
, you know, we could just <i>fix the problem.</i> The problem is only ambig=
uous because the user cannot accurately express what they want. Instead of =
forcing every writer of a class to prevent the ambiguity, let's just allow =
programmers to say what it is that they actually want.<br><br>I don't under=
stand this resistance to such an obvious language fix. The language doesn't=
let us say what we really want to do; the obvious solution is to allow us =
to say what we really want to do. This isn't rocket science here.<br><br>Th=
inking like you're doing is what gives us nightmare library features like `=
std::enable_if` and other similar metaprogramming garbage. It's always easi=
er to just make everyone else do more work than to fix the problem right. Y=
es, they work, but they're horrible to read and painful to use.<br><br>We a=
s C++ programmers need to stop relying on these quick-fix solutions. Isn't =
that why the C++ committee is moving to a faster release cycle? So that we =
can get real fixes for real problems the right way, in a timely manor?<br><=
/div></blockquote><div><br>Indeed, arguing against having a fix is like say=
ing that we shouldn't allow this to work:<br><br><div class=3D"prettyprint"=
style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187,=
187); border-style: solid; border-width: 1px; word-wrap: break-word;"><cod=
e class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color:=
#008;" class=3D"styled-by-prettify">void</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"> </span><span style=3D"color: #606;" class=
=3D"styled-by-prettify">Func</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">(</span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">int</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> i</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">void</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #606;" class=3D"styled-by-prettify">Func</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">(</span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">float</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> f</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br><br></span><span style=3D"color: #606;" class=3D"styled-by-prettify=
">Func</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</s=
pan><span style=3D"color: #066;" class=3D"styled-by-prettify">1.0</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #800;" class=3D"styled-by-prettify">//Ambiguous call</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color=
: #606;" class=3D"styled-by-prettify">Func</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">((</span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">float</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">)</span><span style=3D"color: #066;" class=3D"styled-by-=
prettify">1.0</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </sp=
an><span style=3D"color: #800;" class=3D"styled-by-prettify">//Ambiguity re=
solved</span></div></code></div><br>My proposal is conceptually no differen=
t than this.<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_1022_6791960.1359516353735--
.
Author: Nevin Liber <nevin@eviloverlord.com>
Date: Tue, 29 Jan 2013 21:34:12 -0600
Raw View
--047d7b5da2a577ab8104d4793195
Content-Type: text/plain; charset=ISO-8859-1
On 29 January 2013 21:17, Nicol Bolas <jmckesson@gmail.com> wrote:
>
> Or, you know, we could just *fix the problem.* The problem is only
> ambiguous because the user cannot accurately express what they want.
> Instead of forcing every writer of a class to prevent the ambiguity, let's
> just allow programmers to say what it is that they actually want.
>
> I don't understand this resistance to such an obvious language fix. The
> language doesn't let us say what we really want to do; the obvious solution
> is to allow us to say what we really want to do. This isn't rocket science
> here.
>
*Everyone* who posts here thinks they have the "obvious" solution.
> Thinking like you're doing is what gives us nightmare library features
> like `std::enable_if` and other similar metaprogramming garbage. It's
> always easier to just make everyone else do more work than to fix the
> problem right. Yes, they work, but they're horrible to read and painful to
> use.
>
Okay, I'll bite. What's your "obvious" solution to enable_if? The last
solution, Concepts, is still years in the making...
> We as C++ programmers need to stop relying on these quick-fix solutions.
> Isn't that why the C++ committee is moving to a faster release cycle? So
> that we can get real fixes for real problems the right way, in a timely
> manor?
>
Without destroying the language as a whole in the process.
> --
>
> ---
> 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.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
>
>
>
--
Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
--047d7b5da2a577ab8104d4793195
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On 29 January 2013 21:17, Nicol Bolas <span dir=3D"ltr"><<a href=3D"mail=
to:jmckesson@gmail.com" target=3D"_blank">jmckesson@gmail.com</a>></span=
> wrote:<br><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class=3D"im"><br>Or, you know, we could just <i>fix the problem.</i> T=
he problem is only ambiguous because the user cannot accurately express wha=
t they want. Instead of forcing every writer of a class to prevent the ambi=
guity, let's just allow programmers to say what it is that they actuall=
y want.</div>
<div><br>I don't understand this resistance to such an obvious language=
fix. The language doesn't let us say what we really want to do; the ob=
vious solution is to allow us to say what we really want to do. This isn=
9;t rocket science here.<br>
</div></blockquote><div><br></div><div>*Everyone* who posts here thinks the=
y have the "obvious" solution.</div><div>=A0</div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;pa=
dding-left:1ex">
<div>Thinking like you're doing is what gives us nightmare library feat=
ures like `std::enable_if` and other similar metaprogramming garbage. It=
9;s always easier to just make everyone else do more work than to fix the p=
roblem right. Yes, they work, but they're horrible to read and painful =
to use.<br>
</div></blockquote><div><br></div><div>Okay, I'll bite. =A0What's y=
our "obvious" solution to enable_if? =A0The last solution, Concep=
ts, is still years in the making...</div><div>=A0</div><blockquote class=3D=
"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding=
-left:1ex">
<div>We as C++ programmers need to stop relying on these quick-fix solution=
s. Isn't that why the C++ committee is moving to a faster release cycle=
? So that we can get real fixes for real problems the right way, in a timel=
y manor?<br>
</div></blockquote><div><br></div><div>Without destroying the language as a=
whole in the process.</div><div>=A0</div><blockquote class=3D"gmail_quote"=
style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><d=
iv>
</div><div class=3D"HOEnZb"><div class=3D"h5">
<p></p>
-- <br>
=A0<br>
--- <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%2Bunsubscribe@isocpp.org" target=3D=
"_blank">std-proposals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den" target=3D"_blank">http://groups.google.com/a/isocpp=
..org/group/std-proposals/?hl=3Den</a>.<br>
=A0<br>
=A0<br>
</div></div></blockquote></div><br><br clear=3D"all"><div><br></div>-- <br>=
=A0Nevin ":-)" Liber=A0 <mailto:<a href=3D"mailto:nevin@evilov=
erlord.com" target=3D"_blank">nevin@eviloverlord.com</a>>=A0 (847) 691-1=
404
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
--047d7b5da2a577ab8104d4793195--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 29 Jan 2013 20:10:46 -0800 (PST)
Raw View
------=_Part_240_12506006.1359519046888
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, January 29, 2013 7:34:12 PM UTC-8, Nevin ":-)" Liber wrote:
>
> On 29 January 2013 21:17, Nicol Bolas <jmck...@gmail.com <javascript:>>wrote:
>
>>
>> Or, you know, we could just *fix the problem.* The problem is only
>> ambiguous because the user cannot accurately express what they want.
>> Instead of forcing every writer of a class to prevent the ambiguity, let's
>> just allow programmers to say what it is that they actually want.
>>
>> I don't understand this resistance to such an obvious language fix. The
>> language doesn't let us say what we really want to do; the obvious solution
>> is to allow us to say what we really want to do. This isn't rocket science
>> here.
>>
>
> *Everyone* who posts here thinks they have the "obvious" solution.
>
That doesn't mean that they're all wrong.
Thinking like you're doing is what gives us nightmare library features like
>> `std::enable_if` and other similar metaprogramming garbage. It's always
>> easier to just make everyone else do more work than to fix the problem
>> right. Yes, they work, but they're horrible to read and painful to use.
>>
>
> Okay, I'll bite. What's your "obvious" solution to enable_if? The last
> solution, Concepts, is still years in the making...
>
static if. It's already in development, with successful implementations in
another language in a similar capacity.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_240_12506006.1359519046888
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Tuesday, January 29, 2013 7:34:12 PM UTC-8, Nevin ":-)" Liber wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">On 29 January 2013 21:17, =
Nicol Bolas <span dir=3D"ltr"><<a href=3D"javascript:" target=3D"_blank"=
gdf-obfuscated-mailto=3D"5IJb2UDcho4J">jmck...@gmail.com</a>></span> wr=
ote:<br><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=
=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><br>Or, you know, we could just <i>fix the problem.</i> The problem is=
only ambiguous because the user cannot accurately express what they want. =
Instead of forcing every writer of a class to prevent the ambiguity, let's =
just allow programmers to say what it is that they actually want.</div>
<div><br>I don't understand this resistance to such an obvious language fix=
.. The language doesn't let us say what we really want to do; the obvious so=
lution is to allow us to say what we really want to do. This isn't rocket s=
cience here.<br>
</div></blockquote><div><br></div><div>*Everyone* who posts here thinks the=
y have the "obvious" solution.</div></div></blockquote><div><br>That doesn'=
t mean that they're all wrong.<br><br></div><blockquote class=3D"gmail_quot=
e" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddin=
g-left: 1ex;"><div class=3D"gmail_quote"><div></div><blockquote class=3D"gm=
ail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-le=
ft:1ex">
<div>Thinking like you're doing is what gives us nightmare library features=
like `std::enable_if` and other similar metaprogramming garbage. It's alwa=
ys easier to just make everyone else do more work than to fix the problem r=
ight. Yes, they work, but they're horrible to read and painful to use.<br>
</div></blockquote><div><br></div><div>Okay, I'll bite. What's your "=
obvious" solution to enable_if? The last solution, Concepts, is still=
years in the making...</div></div></blockquote><div><br>static if. It's al=
ready in development, with successful implementations in another language i=
n a similar capacity.</div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_240_12506006.1359519046888--
.
Author: Sebastian Gesemann <s.gesemann@gmail.com>
Date: Wed, 30 Jan 2013 14:36:21 +0100
Raw View
On Wed, Jan 30, 2013 at 4:25 AM, Nicol Bolas wrote:
> Indeed, arguing against having a fix is like saying that we shouldn't allow
> this to work:
>
> void Func(int i);
> void Func(float f);
>
> Func(1.0); //Ambiguous call
> Func((float)1.0); //Ambiguity resolved
>
> My proposal is conceptually no different than this.
Actually, it is different. In this example you did not change the
initialization syntax, but just an argument's expression. The
initialization syntax and the argument expressions are two separate
things. You propose to add two additional initialization syntaxes
instead of making one syntax work for more cases. It's a hack, a quick
fix for odd overload resolution rules and vector<int> unfortunately
relying on these odd overload resolution rules to disambiguate between
two constructors merely based on the kind of initialization syntax and
not the list of arguments like it probably should. Your fix stops
working when you have to think about how you should implment
allocator<>::construct. Ideally the user of this construct function
template is able to control how the object should be initialized by
using appropriate arguments so that overload resolution picks the
right one. You just added yet another mechanism of control that
doesn't work in the contexts like allocator<>::construct unless you
add special casing for {c:} and {l:} via providing construct_l and
construct_c or something like this. This special casing would be
viral, too. You'd need this special casing also in make_shared and
emplace_back for example. But this special casing would already be
possible in C++11 today without {c:} and {l:}.
I think the idea of adding a first dummy argument for disambiguation
is better because it does not invent new initialization syntaxes but
just make one syntax work for all cases. But it's still not enough
bang for the buck if you ask me. This also seems like yet another hack
that just tries to cover up funny overload resolution rules.
> We as C++ programmers need to stop relying on these quick-fix
> solutions.
Including yours?
On Wed, Jan 30, 2013 at 4:34 AM, Nevin Liber wrote:
> On 29 January 2013 21:17, Nicol Bolas wrote:
>
>> Thinking like you're doing is what gives us nightmare library features
>> like `std::enable_if` and other similar metaprogramming garbage. It's always
>> easier to just make everyone else do more work than to fix the problem
>> right. Yes, they work, but they're horrible to read and painful to use.
>
> Okay, I'll bite. What's your "obvious" solution to enable_if? The last
> solution, Concepts, is still years in the making...
Concepts really tried to kill three birds with one stone:
- constraining templates
- modular type checking (checking templates before instantiation)
- concept-based overloading
enable_if ist just about the first one and probably much easier to
implement as a core language feature.
Cheers!
SG
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Wed, 30 Jan 2013 05:50:25 -0800 (PST)
Raw View
------=_Part_239_22298313.1359553826038
Content-Type: text/plain; charset=ISO-8859-1
On Wednesday, January 30, 2013 7:05:50 AM UTC+4, Nicol Bolas wrote:
> On Tuesday, January 29, 2013 6:28:34 AM UTC-8, Nikolay Ivchenkov wrote:
>>
>> You are suggesting two different kinds of initialization, rather than one
>> uniform initialization syntax (as several people already noticed).
>>
>
> I'm suggesting two slight variations of initialization syntax
>
That sounds like "slightly pregnant". {c:} and {l:} are two different
syntactic constructs. Similarly, static_cast<T>(x) and const_cast<T>(x) are
two different syntactic constructs.
> so that the user can express what they're getting.
>
This goal can be achieved by replacing one pseudo-uniform initialization
syntax with a combination of _different_ syntactic constructs. {c:} + {l:}
is one of possible combinations, but, IMO, it's not the best option.
> The only difference is which constructors are considered; all of the other
> aspects of initialization (initializing aggregates, figuring out what type
> to use, etc) remain the same. In short, 90% of the text around such
> braced-init-lists in the standard will be identical; all that changes is
> the part of 13.3.1.7 that says which constructors are considered.
>
If that's so simple, why don't you provide exact wording changes?
No, I would like to have a modifier ~, or +, or something else for a
>> braced-init-list such that
>>
>> AggregateType a = ~ braced-init-list;
>>
>> and
>>
>> AggregateType a ( ~ braced-init-list );
>>
>
> That's what {l:} does.
>
Your description of {l:} doesn't imply that.
Furthermore, {l:} is not enough, because there's no way to have similar
> behavior but only consider regular constructors.
>
We have () for regular constructors.
> Of course, you don't want that because you don't want uniform
> initialization syntax at all. You don't *want* users to use {} syntax
> everywhere to initialize things.
>
() could be used everywhere if we would have a regular declaration syntax,
e.g.:
void f(/std::vector<int> v(n)); // default value of v is
std::vector<int>(n)
> Personally, I've never understood this notion that aggregate
> initialization is in any way like initializer_list initialization. It's far
> more like constructor syntax than initializer_lists, since aggregates don't
> have to contain the same types.
>
....while objects with arbitrary constructors don't have to contain any
sequences at all. What is common between aggregates and objects with
arbitrary constructors? Why should we use different syntax for built-in
arrays / std::array and std::vector?
int arr[] = {c: 10, 20};
std::array<int, 2> a{c: 10, 20};
std::vector<int> v{l: 10, 20};
> That's why {} should only have considered regular constructors to begin
> with, forcing the use of {{}} for initializer_list initialization.
>
You'll get similar issue with nested braced-init-list: {x} can match
parameters of type std::size_t and of type std::initializer_list<T>.
On Wednesday, January 30, 2013 7:17:55 AM UTC+4, Nicol Bolas wrote:
>
> On Tuesday, January 29, 2013 10:04:51 AM UTC-8, vattila...@yahoo.co.ukwrote:
>>
>> On Tuesday, 29 January 2013 14:41:29 UTC, Sebastian Gesemann wrote:
>> > Anyways, tbh, it doesn't change how I feel about your proposal. It
>> > does not seem to fit well into the rest of c++ and the need to special
>> > case functions like make_shared or construct is bad.
>>
>> On a related note, I just browsed the C++ Standard Library Active Issues
>> List (N3516) and noticed issue 2089, "std::allocator::construct should use
>> uniform initialization".
>>
>> http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2089
>>
>> It proposes to solve the problem in emplace_back (currently not allowing
>> aggregate-initialization and list-initialization) by meta-programming using
>> type traits. These programming techniques are now part of a
>> well-established toolbox for controlling overload resolution, and the mood
>> may very well be that this is sufficient to deal with the initialization
>> quirks in the language as well.
>>
>
> ....
>
> Granted, there would be no need for this deduction stuff if they had {c:},
> which would be effectively equivalent (save never using initializer_list
> constructors without explicitly specifying it, but I would consider that an
> improvement)
>
We already found out that simple replacement of (items...) with {c:
items...} is able to break a lot of existing code. You may be sure that if
such a change will be accepted, many people will curse the author of the
proposal and the committee.
On Wednesday, January 30, 2013 8:10:46 AM UTC+4, Nicol Bolas wrote:
>
> On Tuesday, January 29, 2013 7:34:12 PM UTC-8, Nevin ":-)" Liber wrote:
>>
>>
>> Okay, I'll bite. What's your "obvious" solution to enable_if? The last
>> solution, Concepts, is still years in the making...
>>
>
> static if.
>
I wouldn't consider static if as a full-fledged replacement for enable_if.
> It's already in development, with successful implementations in another
> language in a similar capacity.
>
AFAIK, "another language" does not have two-phase name lookup.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_239_22298313.1359553826038
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Wednesday, January 30, 2013 7:05:50 AM UTC+4, Nicol Bolas wrote:<br><blo=
ckquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-=
left: 1px #ccc solid;padding-left: 1ex;">On Tuesday, January 29, 2013 6:28:=
34 AM UTC-8, Nikolay Ivchenkov wrote:<blockquote class=3D"gmail_quote" styl=
e=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex=
">You are suggesting two different kinds of initialization, rather than one=
uniform initialization syntax (as several people already noticed).<br></bl=
ockquote><div><br>I'm suggesting two slight variations of initialization sy=
ntax</div></blockquote><div><br>That sounds like "slightly pregnant". {c:} =
and {l:} are two different syntactic constructs. Similarly, static_cast<=
T>(x) and const_cast<T>(x) are two different syntactic constructs.=
<br> <br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;ma=
rgin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>so th=
at the user can express what they're getting.</div></blockquote><div><br>Th=
is goal can be achieved by replacing one pseudo-uniform initialization synt=
ax with a combination of _different_ syntactic constructs. {c:} + {l:} is o=
ne of possible combinations, but, IMO, it's not the best option.<br> <=
/div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;"><div> The only difference=
is which constructors are considered; all of the other aspects of initiali=
zation (initializing aggregates, figuring out what type to use, etc) remain=
the same. In short, 90% of the text around such braced-init-lists in the s=
tandard will be identical; all that changes is the part of 13.3.1.7 that sa=
ys which constructors are considered.<br></div></blockquote><div><br>If tha=
t's so simple, why don't you provide exact wording changes?<br><br></div><b=
lockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;borde=
r-left: 1px #ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote=
" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-le=
ft:1ex"><div>No, I would like to have a modifier ~, or +, or something else=
for a braced-init-list such that<br><br> AggregateType a=
=3D ~ braced-init-list;<br><br>and<br><br> AggregateType=
a ( ~ braced-init-list );<br></div></blockquote><div><br>That's what {l:} =
does.<br></div></blockquote><div><br>Your description of {l:} doesn't imply=
that.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;ma=
rgin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>Furth=
ermore, {l:} is not enough, because there's no way to have similar behavior=
but only consider regular constructors.</div></blockquote><div><br>We have=
() for regular constructors.<br> </div><blockquote class=3D"gmail_quo=
te" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddi=
ng-left: 1ex;"><div> Of course, you don't want that because you don't want =
uniform initialization syntax at all. You don't <i>want</i> users to use {}=
syntax everywhere to initialize things.</div></blockquote><div><br>() coul=
d be used everywhere if we would have a regular declaration syntax, e.g.:<b=
r><br> void f(/std::vector<int> v(n)); // default v=
alue of v is std::vector<int>(n)<br> </div><blockquote class=3D"=
gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc so=
lid;padding-left: 1ex;"><div>Personally, I've never understood this notion =
that aggregate initialization is in any way like initializer_list initializ=
ation. It's far more like constructor syntax than initializer_lists, since =
aggregates don't have to contain the same types.</div></blockquote><div><br=
>...while objects with arbitrary constructors don't have to contain any seq=
uences at all. What is common between aggregates and objects with arbitrary=
constructors? Why should we use different syntax for built-in arrays / std=
::array and std::vector?<br><br> int arr[] =3D {c: 10, 20=
};<br> std::array<int, 2> a{c: 10, 20};<br> &n=
bsp; std::vector<int> v{l: 10, 20};<br> <br></div><blockqu=
ote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left=
: 1px #ccc solid;padding-left: 1ex;"><div> That's why {} should only have c=
onsidered regular constructors to begin with, forcing the use of {{}} for i=
nitializer_list initialization.</div></blockquote><div><br>You'll get simil=
ar issue with nested braced-init-list: {x} can match parameters of type std=
::size_t and of type std::initializer_list<T>.<br><br>On Wednesday, J=
anuary 30, 2013 7:17:55 AM UTC+4, Nicol Bolas wrote:<blockquote class=3D"gm=
ail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc soli=
d;padding-left: 1ex;">On Tuesday, January 29, 2013 10:04:51 AM UTC-8, <a>va=
ttila...@yahoo.co.uk</a> wrote:<blockquote class=3D"gmail_quote" style=3D"m=
argin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex">
<div style=3D"margin-bottom:0cm">On Tuesday, 29 January
2013 14:41:29 UTC, Sebastian Gesemann wrote:</div><div style=3D"margin-bott=
om:0cm">> Anyways, tbh, it
doesn't change how I feel about your proposal. It</div><div style=3D"margin=
-bottom:0cm">> does not seem to
fit well into the rest of c++ and the need to special</div><div style=3D"ma=
rgin-bottom:0cm">> case functions
like make_shared or construct is bad.</div><div style=3D"margin-bottom:0cm"=
> </div><div style=3D"margin-bottom:0cm">On a related note, I
just browsed the C++ Standard Library Active Issues List (N3516) and
noticed issue 2089, "std::allocator::construct should use
uniform initialization".</div><div style=3D"margin-bottom:0cm"> </div>=
<div style=3D"margin-bottom:0cm"><a href=3D"http://www.open-std.org/jtc1/sc=
22/wg21/docs/lwg-active.html#2089" target=3D"_blank">http://www.open-std.or=
g/jtc1/<wbr>sc22/wg21/docs/lwg-active.<wbr>html#2089</a></div><div style=3D=
"margin-bottom:0cm"> </div><div style=3D"margin-bottom:0cm">It propose=
s to solve
the problem in emplace_back (currently not allowing
aggregate-initialization and list-initialization) by meta-programming
using type traits. These programming techniques are now part of a
well-established toolbox for controlling overload resolution,
and the mood may very well be that this is sufficient to deal with
the initialization quirks in the language as well.</div></blockquote><div><=
br>....<br><br>Granted,
there would be no need for this deduction stuff if they had {c:}, which
would be effectively equivalent (save never using initializer_list=20
constructors without explicitly specifying it, but I would consider that
an improvement)<br></div></blockquote><div><br>We already found out=20
that simple replacement of (items...) with {c: items...} is able to=20
break a lot of existing code. You may be sure that if such a change will
be accepted, many people will curse the author of the proposal and the=20
committee.<br><br>On Wednesday, January 30, 2013 8:10:46 AM UTC+4, Nicol Bo=
las wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:=
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On Tuesday, January =
29, 2013 7:34:12 PM UTC-8, Nevin ":-)" Liber wrote:<blockquote class=3D"gma=
il_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;pa=
dding-left:1ex"><div class=3D"gmail_quote"><div><br></div><div>Okay, I'll b=
ite. What's your "obvious" solution to enable_if? The last solu=
tion, Concepts, is still years in the making...</div></div></blockquote><di=
v><br>static if.</div></blockquote><div><br>I wouldn't consider static if a=
s a full-fledged replacement for enable_if.<br> <br></div><blockquote =
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1p=
x #ccc solid;padding-left: 1ex;"><div> It's already in development, with su=
ccessful implementations in another language in a similar capacity.</div></=
blockquote><div><br>AFAIK, "another language" does not have two-phase name =
lookup.<br></div></div></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_239_22298313.1359553826038--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Wed, 30 Jan 2013 12:50:13 -0800 (PST)
Raw View
------=_Part_96_24462207.1359579013864
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Wednesday, January 30, 2013 5:50:25 AM UTC-8, Nikolay Ivchenkov wrote:
>
> On Wednesday, January 30, 2013 7:05:50 AM UTC+4, Nicol Bolas wrote:
>
>> On Tuesday, January 29, 2013 6:28:34 AM UTC-8, Nikolay Ivchenkov wrote:
>>>
>>> You are suggesting two different kinds of initialization, rather than=
=20
>>> one uniform initialization syntax (as several people already noticed).
>>>
>>
>> I'm suggesting two slight variations of initialization syntax
>>
>
> That sounds like "slightly pregnant". {c:} and {l:} are two different=20
> syntactic constructs. Similarly, static_cast<T>(x) and const_cast<T>(x) a=
re=20
> two different syntactic constructs.
>
{c:} and {l:} are conceptually like the difference between=20
static_cast<float> and static_cast<int> than static_cast and const_cast.=20
They are two mechanisms that operate similarly: they modify how their=20
parameter is interpreted by subsequent code. Which modification they=20
perform is based on the parameter.
The difference is that it is syntactically within the "expression" rather=
=20
than outside of it.
so that the user can express what they're getting.
>>
>
> This goal can be achieved by replacing one pseudo-uniform initialization=
=20
> syntax with a combination of _different_ syntactic constructs. {c:} + {l:=
}=20
> is one of possible combinations, but, IMO, it's not the best option.
>
My point is that your opinion is based on your belief that initialization=
=20
should not be uniform, that aggregate initialization should be considered a=
=20
form of list initialization, and that if you want to initialize an object=
=20
that may or may not be an aggregate, you should use std::enable_if or other=
=20
compile-time testing mechanisms to do so.
The only difference is which constructors are considered; all of the other=
=20
>> aspects of initialization (initializing aggregates, figuring out what ty=
pe=20
>> to use, etc) remain the same. In short, 90% of the text around such=20
>> braced-init-lists in the standard will be identical; all that changes is=
=20
>> the part of 13.3.1.7 that says which constructors are considered.
>>
>
> If that's so simple, why don't you provide exact wording changes?
>
First, I never said that the wording was "simple"; I said that it was *
localized*. I was saying that this proposal only affects the overload=20
resolution rules of uniform initialization.
Second, I wanted to pin down the feature and make sure that there are no=20
issues with it before getting into details of wording. Also, while I know=
=20
the general form it would take and what would need to be changed (just=20
8.5.4 to define the grammar, and 13.3.1.7 to express the meaning of that=20
grammar), I'm less certain of my understanding of what the right way to=20
make that change is.
Specifically, 13.3.1.7 does not make mention of braced-init-list's at all;=
=20
it makes mention of list-initialization vs. copy-list-initialization. I=20
don't know if the language simply worked out that way or if it was=20
deliberate, so I don't feel comfortable modifying this section to mention=
=20
some new `qualified-braced-init-list` subcategory. But the only way around=
=20
that is to have 8.5.4 define several sub-types of list-initialization for=
=20
the different constructor methodologies.
But this is all merely a wording implementation detail; it has no material=
=20
effect on the behavior. I didn't want to commit to a wording until I had a=
=20
syntax I was happy with.
No, I would like to have a modifier ~, or +, or something else for a=20
>>> braced-init-list such that
>>>
>>> AggregateType a =3D ~ braced-init-list;
>>>
>>> and
>>>
>>> AggregateType a ( ~ braced-init-list );
>>>
>>
>> That's what {l:} does.
>>
>
> Your description of {l:} doesn't imply that.
>
The proposal says:
=93l=94: Call an initializer_list constructor.
>
And it also says:
These variation *only* affect which constructors are considered during=20
> overload resolution; in every other respect, they work like a regular=20
> braced-init-list.
>
I'm not sure how I could make it more clear that this syntax only affects=
=20
constructor selection, that every other aspect of braced-init-list=20
initialization is unaffected. Obviously adding spec wording would make it=
=20
clearer, but I suppose I could reorganize the Design Overview section.
Personally, I've never understood this notion that aggregate initialization=
=20
>> is in any way like initializer_list initialization. It's far more like=
=20
>> constructor syntax than initializer_lists, since aggregates don't have t=
o=20
>> contain the same types.
>>
>
> ...while objects with arbitrary constructors don't have to contain any=20
> sequences at all. What is common between aggregates and objects with=20
> arbitrary constructors? Why should we use different syntax for built-in=
=20
> arrays / std::array and std::vector?
>
> int arr[] =3D {c: 10, 20};
> std::array<int, 2> a{c: 10, 20};
> std::vector<int> v{l: 10, 20};
>
Because the user needs that specificity for objects with constructors:
std::vector<int> v1{l: 10, 20};
std::vector<int> v2{c: 10, 20};
These do different things.
If I'm in a template context and I have some type T, which may or may not=
=20
be an aggregate, I need to tell the compiler which one I mean.
Thus:
template<typename T>
void Func()
{
T arr{l: 10, 20};
//Do stuff with arr
}
void Func<int[2]>();
void Func<std::array<int, 2>>();
void Func<std::vector<int>>();
Where `T` is any form of container which can be initialized with {l:}=20
syntax with two elements.
Your way would require that I do some std::enable_if detection and so forth=
=20
to figure out if `T` is an aggregate and use a different codepath or=20
whatever. My way is far more human readable.
That's why {} should only have considered regular constructors to begin=20
>> with, forcing the use of {{}} for initializer_list initialization.
>>
>
> You'll get similar issue with nested braced-init-list: {x} can match=20
> parameters of type std::size_t and of type std::initializer_list<T>.
>
This is a problem for which we presently have the means to resolve: by=20
using an explicit typename. The general solution for explicitly resolving=
=20
ambiguity is using explicit syntax to make clear what was implicit before.
All I'm proposing is an appropriate ambiguity resolution syntax for uniform=
=20
initialization. Allow the user to specify if they want to call=20
non-initializer_list constructors or initializer_list constructors, or=20
which to prefer?
On Wednesday, January 30, 2013 7:17:55 AM UTC+4, Nicol Bolas wrote:
>>
>> On Tuesday, January 29, 2013 10:04:51 AM UTC-8, vattila...@yahoo.co.ukwr=
ote:
>>>
>>> On Tuesday, 29 January 2013 14:41:29 UTC, Sebastian Gesemann wrote:
>>> > Anyways, tbh, it doesn't change how I feel about your proposal. It
>>> > does not seem to fit well into the rest of c++ and the need to specia=
l
>>> > case functions like make_shared or construct is bad.
>>> =20
>>> On a related note, I just browsed the C++ Standard Library Active Issue=
s=20
>>> List (N3516) and noticed issue 2089, "std::allocator::construct should =
use=20
>>> uniform initialization".
>>> =20
>>> http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2089
>>> =20
>>> It proposes to solve the problem in emplace_back (currently not allowin=
g=20
>>> aggregate-initialization and list-initialization) by meta-programming u=
sing=20
>>> type traits. These programming techniques are now part of a=20
>>> well-established toolbox for controlling overload resolution, and the m=
ood=20
>>> may very well be that this is sufficient to deal with the initializatio=
n=20
>>> quirks in the language as well.
>>>
>>
>> ....
>>
>> Granted, there would be no need for this deduction stuff if they had=20
>> {c:}, which would be effectively equivalent (save never using=20
>> initializer_list constructors without explicitly specifying it, but I wo=
uld=20
>> consider that an improvement)
>>
>
> We already found out that simple replacement of (items...) with {c:=20
> items...} is able to break a lot of existing code. You may be sure that i=
f=20
> such a change will be accepted, many people will curse the author of the=
=20
> proposal and the committee.
>
Did we? In what case would {c:} usage for all of the currently=20
constructor-based initialization break code?
Indeed, as vattila pointed out, we already have a defect report suggesting=
=20
that we allow allocator_traits<>::construct to detect aggregates and=20
different constructor types, and apply uniform initialization in certain=20
cases. The proposed mechanism is the *exact equivalent* of the proposal's=
=20
{cl:} behavior.
So I would say that {c:} does not break any code that currently uses ()=20
behavior. Outside of forbidding narrowing and other elements of uniform=20
initialization and such.
--=20
---=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/?hl=3Den.
------=_Part_96_24462207.1359579013864
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Wednesday, January 30, 2013 5:50:25 AM UTC-8, Nikolay Ivchenkov wrote:<b=
lockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;borde=
r-left: 1px #ccc solid;padding-left: 1ex;">On Wednesday, January 30, 2013 7=
:05:50 AM UTC+4, Nicol Bolas wrote:<br><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1=
ex">On Tuesday, January 29, 2013 6:28:34 AM UTC-8, Nikolay Ivchenkov wrote:=
<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;borde=
r-left:1px #ccc solid;padding-left:1ex">You are suggesting two different ki=
nds of initialization, rather than one uniform initialization syntax (as se=
veral people already noticed).<br></blockquote><div><br>I'm suggesting two =
slight variations of initialization syntax</div></blockquote><div><br>That =
sounds like "slightly pregnant". {c:} and {l:} are two different syntactic =
constructs. Similarly, static_cast<T>(x) and const_cast<T>(x) a=
re two different syntactic constructs.<br></div></blockquote><div><br>{c:} =
and {l:} are conceptually like the difference between static_cast<float&=
gt; and static_cast<int> than static_cast and const_cast. They are tw=
o mechanisms that operate similarly: they modify how their parameter is int=
erpreted by subsequent code. Which modification they perform is based on th=
e parameter.<br><br>The difference is that it is syntactically within the "=
expression" rather than outside of it.<br><br></div><blockquote class=3D"gm=
ail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc soli=
d;padding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"margin:0;m=
argin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>so that =
the user can express what they're getting.</div></blockquote><div><br>This =
goal can be achieved by replacing one pseudo-uniform initialization syntax =
with a combination of _different_ syntactic constructs. {c:} + {l:} is one =
of possible combinations, but, IMO, it's not the best option.<br></div></bl=
ockquote><div><br>My point is that your opinion is based on your belief tha=
t initialization should not be uniform, that aggregate initialization shoul=
d be considered a form of list initialization, and that if you want to init=
ialize an object that may or may not be an aggregate, you should use std::e=
nable_if or other compile-time testing mechanisms to do so.<br><br><blockqu=
ote style=3D"margin: 0px 0px 0px 0.8ex; border-left: 1px solid rgb(204, 204=
, 204); padding-left: 1ex;" class=3D"gmail_quote"><div class=3D"GAK2G4EDL5"=
><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;bord=
er-left:1px #ccc solid;padding-left:1ex"><div>
The only difference is which constructors are considered; all of the=20
other aspects of initialization (initializing aggregates, figuring out=20
what type to use, etc) remain the same. In short, 90% of the text around
such braced-init-lists in the standard will be identical; all that=20
changes is the part of 13.3.1.7 that says which constructors are=20
considered.<br></div></blockquote></div><br>If that's so simple, why don't =
you provide exact wording changes?<br></blockquote><br>First, I never said =
that the wording was "simple"; I said that it was <i>localized</i>. I was s=
aying that this proposal only affects the overload resolution rules of unif=
orm initialization.<br><br>Second, I wanted to pin down the feature and mak=
e sure that there are no issues with it before getting into details of word=
ing. Also, while I know the general form it would take and what would need =
to be changed (just 8.5.4 to define the grammar, and 13.3.1.7 to express th=
e meaning of that grammar), I'm less certain of my understanding of what th=
e right way to make that change is.<br><br>Specifically, 13.3.1.7 does not =
make mention of braced-init-list's at all; it makes mention of list-initial=
ization vs. copy-list-initialization. I don't know if the language simply w=
orked out that way or if it was deliberate, so I don't feel comfortable mod=
ifying this section to mention some new `qualified-braced-init-list` subcat=
egory. But the only way around that is to have 8.5.4 define several sub-typ=
es of list-initialization for the different constructor methodologies.<br><=
br>But this is all merely a wording implementation detail; it has no materi=
al effect on the behavior. I didn't want to commit to a wording until I had=
a syntax I was happy with.<br><br></div><blockquote class=3D"gmail_quote" =
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-l=
eft: 1ex;"><div></div><blockquote class=3D"gmail_quote" style=3D"margin:0;m=
argin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote c=
lass=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #c=
cc solid;padding-left:1ex"><div>No, I would like to have a modifier ~, or +=
, or something else for a braced-init-list such that<br><br> &nb=
sp; AggregateType a =3D ~ braced-init-list;<br><br>and<br><br> &=
nbsp; AggregateType a ( ~ braced-init-list );<br></div></blockquote><div><b=
r>That's what {l:} does.<br></div></blockquote><div><br>Your description of=
{l:} doesn't imply that.<br></div></blockquote><div><br>The proposal says:=
<br><br><blockquote style=3D"margin: 0px 0px 0px 0.8ex; border-left: 1px so=
lid rgb(204, 204, 204); padding-left: 1ex;" class=3D"gmail_quote"><span sty=
le=3D"color: rgb(11, 83, 148);">=93<span><code>l</code></span>=94: Call an =
initializer_list
constructor.</span><br></blockquote><br>And it also say=
s:<br><br><blockquote style=3D"margin: 0px 0px 0px 0.8ex; border-left: 1px =
solid rgb(204, 204, 204); padding-left: 1ex;" class=3D"gmail_quote"><span s=
tyle=3D"color: rgb(61, 133, 198);">These variation <span><em>only</em></spa=
n> affect which constructors are considered
during overload resolution; in every other respect, they work l=
ike a regular
braced-init-list.</span><br></blockquote><div><br>I'm not sure =
how I could make it more clear that this syntax only affects constructor se=
lection, that every other aspect of braced-init-list initialization is unaf=
fected. Obviously adding spec wording would make it clearer, but I suppose =
I could reorganize the Design Overview section.<br></div><br></div><blockqu=
ote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left=
: 1px #ccc solid;padding-left: 1ex;"><div></div><blockquote class=3D"gmail_=
quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;paddi=
ng-left:1ex"><div>Personally, I've never understood this notion that aggreg=
ate initialization is in any way like initializer_list initialization. It's=
far more like constructor syntax than initializer_lists, since aggregates =
don't have to contain the same types.</div></blockquote><div><br>...while o=
bjects with arbitrary constructors don't have to contain any sequences at a=
ll. What is common between aggregates and objects with arbitrary constructo=
rs? Why should we use different syntax for built-in arrays / std::array and=
std::vector?<br><br> int arr[] =3D {c: 10, 20};<br> =
; std::array<int, 2> a{c: 10, 20};<br> =
std::vector<int> v{l: 10, 20};<br></div></blockquote><div><br>Because=
the user needs that specificity for objects with constructors:<br><br><div=
class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); borde=
r-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-w=
rap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"=
><span style=3D"color: #000;" class=3D"styled-by-prettify">std</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify">vector</span><span style=3D"col=
or: #080;" class=3D"styled-by-prettify"><int></span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> v1</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">l</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">:</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">10=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #066;" class=3D"styled-by-prettify">20</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">};</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"><br>std</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify">vector</span><span style=3D"color: #080;" class=3D"styl=
ed-by-prettify"><int></span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> v2</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
>c</span><span style=3D"color: #660;" class=3D"styled-by-prettify">:</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span sty=
le=3D"color: #066;" class=3D"styled-by-prettify">10</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=
=3D"styled-by-prettify">20</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">};</span></div></code></div><br>These do different things.<=
br><br>If I'm in a template context and I have some type T, which may or ma=
y not be an aggregate, I need to tell the compiler which one I mean.<br><br=
>Thus:<br><br><div class=3D"prettyprint" style=3D"background-color: rgb(250=
, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; border-=
width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=
=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">template</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
><</span><span style=3D"color: #008;" class=3D"styled-by-prettify">typen=
ame</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> T</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">></span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">void</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #60=
6;" class=3D"styled-by-prettify">Func</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">()</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br> T arr</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
>l</span><span style=3D"color: #660;" class=3D"styled-by-prettify">:</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span sty=
le=3D"color: #066;" class=3D"styled-by-prettify">10</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=
=3D"styled-by-prettify">20</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">};</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br> </span><span style=3D"color: #800;" class=3D"styled-by-p=
rettify">//Do stuff with arr</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">}</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify"=
>void</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </sp=
an><span style=3D"color: #606;" class=3D"styled-by-prettify">Func</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">int</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">[</span><span style=3D"color: #06=
6;" class=3D"styled-by-prettify">2</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">]>();</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">void</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-prettif=
y">Func</span><span style=3D"color: #660;" class=3D"styled-by-prettify"><=
;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">std</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify">array</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=3D"co=
lor: #008;" class=3D"styled-by-prettify">int</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"styl=
ed-by-prettify">2</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">>>();</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">void</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </s=
pan><span style=3D"color: #606;" class=3D"styled-by-prettify">Func</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify">std</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify">vector</span><span style=3D"color: #080;=
" class=3D"styled-by-prettify"><int></span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">>();</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br></span></div></code></div><br>Where `T` is=
any form of container which can be initialized with {l:} syntax with two e=
lements.<br><br>Your way would require that I do some std::enable_if detect=
ion and so forth to figure out if `T` is an aggregate and use a different c=
odepath or whatever. My way is far more human readable.<br><br></div><block=
quote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-le=
ft: 1px #ccc solid;padding-left: 1ex;"><div></div><blockquote class=3D"gmai=
l_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;pad=
ding-left:1ex"><div> That's why {} should only have considered regular cons=
tructors to begin with, forcing the use of {{}} for initializer_list initia=
lization.</div></blockquote><div><br>You'll get similar issue with nested b=
raced-init-list: {x} can match parameters of type std::size_t and of type s=
td::initializer_list<T>.<br></div></blockquote><div><br>This is a pro=
blem for which we presently have the means to resolve: by using an explicit=
typename. The general solution for explicitly resolving ambiguity is using=
explicit syntax to make clear what was implicit before.<br><br>All I'm pro=
posing is an appropriate ambiguity resolution syntax for uniform initializa=
tion. Allow the user to specify if they want to call non-initializer_list c=
onstructors or initializer_list constructors, or which to prefer?<br><br></=
div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;"><div>On Wednesday, January=
30, 2013 7:17:55 AM UTC+4, Nicol Bolas wrote:<blockquote class=3D"gmail_qu=
ote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding=
-left:1ex">On Tuesday, January 29, 2013 10:04:51 AM UTC-8, <a>vattila...@ya=
hoo.co.uk</a> wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;mar=
gin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex">
<div style=3D"margin-bottom:0cm">On Tuesday, 29 January
2013 14:41:29 UTC, Sebastian Gesemann wrote:</div><div style=3D"margin-bott=
om:0cm">> Anyways, tbh, it
doesn't change how I feel about your proposal. It</div><div style=3D"margin=
-bottom:0cm">> does not seem to
fit well into the rest of c++ and the need to special</div><div style=3D"ma=
rgin-bottom:0cm">> case functions
like make_shared or construct is bad.</div><div style=3D"margin-bottom:0cm"=
> </div><div style=3D"margin-bottom:0cm">On a related note, I
just browsed the C++ Standard Library Active Issues List (N3516) and
noticed issue 2089, "std::allocator::construct should use
uniform initialization".</div><div style=3D"margin-bottom:0cm"> </div>=
<div style=3D"margin-bottom:0cm"><a href=3D"http://www.open-std.org/jtc1/sc=
22/wg21/docs/lwg-active.html#2089" target=3D"_blank">http://www.open-std.or=
g/jtc1/<wbr>sc22/wg21/docs/lwg-active.<wbr>html#2089</a></div><div style=3D=
"margin-bottom:0cm"> </div><div style=3D"margin-bottom:0cm">It propose=
s to solve
the problem in emplace_back (currently not allowing
aggregate-initialization and list-initialization) by meta-programming
using type traits. These programming techniques are now part of a
well-established toolbox for controlling overload resolution,
and the mood may very well be that this is sufficient to deal with
the initialization quirks in the language as well.</div></blockquote><div><=
br>....<br><br>Granted,
there would be no need for this deduction stuff if they had {c:}, which
would be effectively equivalent (save never using initializer_list=20
constructors without explicitly specifying it, but I would consider that
an improvement)<br></div></blockquote><div><br>We already found out=20
that simple replacement of (items...) with {c: items...} is able to=20
break a lot of existing code. You may be sure that if such a change will
be accepted, many people will curse the author of the proposal and the=20
committee.</div></div></blockquote><div><br>Did we? In what case would {c:}=
usage for all of the currently constructor-based initialization break code=
?<br><br>Indeed, as vattila pointed out, we already have a defect report su=
ggesting that we allow allocator_traits<>::construct to detect aggreg=
ates and different constructor types, and apply uniform initialization in c=
ertain cases. The proposed mechanism is the <i>exact equivalent</i> of the =
proposal's {cl:} behavior.<br><br>So I would say that {c:} does not break a=
ny code that currently uses () behavior. Outside of forbidding narrowing an=
d other elements of uniform initialization and such.<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_96_24462207.1359579013864--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Wed, 30 Jan 2013 13:23:01 -0800 (PST)
Raw View
------=_Part_24_14731543.1359580981423
Content-Type: text/plain; charset=ISO-8859-1
On Wednesday, January 30, 2013 5:36:21 AM UTC-8, Sebastian Gesemann wrote:
>
> On Wed, Jan 30, 2013 at 4:25 AM, Nicol Bolas wrote:
> > Indeed, arguing against having a fix is like saying that we shouldn't
> allow
> > this to work:
> >
> > void Func(int i);
> > void Func(float f);
> >
> > Func(1.0); //Ambiguous call
> > Func((float)1.0); //Ambiguity resolved
> >
> > My proposal is conceptually no different than this.
>
> Actually, it is different. In this example you did not change the
> initialization syntax, but just an argument's expression. The
> initialization syntax and the argument expressions are two separate
> things.
That's an implementation difference only; *conceptually *they are the same:
there is an ambiguity, so you add a syntax construct to resolve it. Yes,
one changes the argument's expression, but braced-init-lists aren't
expressions. They will therefore have to use different syntax from
expressions to resolve the ambiguity.
Would it make you feel better if it were some kind of prefix syntax of the
{} rather than a syntax within the {} enclosure? Because the form of the
syntax is personal preference; what I'm concerned with is the behavior. I
choose the syntax I did because it doesn't cause any parsing problems with
existing code, thus allowing me to use special identifiers rather than new
keywords or oddball symbols.
A prefix syntax would be much harder to include the 4 use cases I outlined.
> You propose to add two additional initialization syntaxes
> instead of making one syntax work for more cases. It's a hack, a quick
> fix for odd overload resolution rules and vector<int> unfortunately
> relying on these odd overload resolution rules to disambiguate between
> two constructors merely based on the kind of initialization syntax and
> not the list of arguments like it probably should.
The fact is, once uniform initialization shipped with the ambiguity as part
of it, with the ability for {} to resolve to an initializer_list
constructor *at all*, the damage was done. And since we can't remove that
feature, our only choice is to find a way to let the user specify how *they*want the ambiguity resolved.
That's all I'm proposing here. It's not a different initialization syntax;
it's a slight modification of the *same* initialization syntax. In every
other respect, it works identically to {}.
Your fix stops
> working when you have to think about how you should implment
> allocator<>::construct. Ideally the user of this construct function
> template is able to control how the object should be initialized by
> using appropriate arguments so that overload resolution picks the
> right one. You just added yet another mechanism of control that
> doesn't work in the contexts like allocator<>::construct unless you
> add special casing for {c:} and {l:} via providing construct_l and
> construct_c or something like this. This special casing would be
> viral, too. You'd need this special casing also in make_shared and
> emplace_back for example. But this special casing would already be
> possible in C++11 today without {c:} and {l:}.
>
This argument is off-topic. You're talking about the problem of forwarding
initialization intent. That's a problem that exists *now*; there's no way
to make the called function use a set of parameters with {} syntax instead
of () syntax. My proposal does not aim to fix this situation.
In short, forwarding initialization intent is a problem now. It would be a
problem even with this proposal. But this proposal is *not trying* to solve
that problem. So the fact that it's a problem is irrelevant to this
discussion. Yes, the proposal makes the problem slightly worse in that
there are more forms of initialization to forward. But we already have two
forms currently: braced-init-list vs. () syntax.
Adding variations of braced-init-lists to any such resolution will be no
more difficult than resolving the problem in the first place.
Personally, I don't think the problem can be resolved. At some level, we
are going to have to accept that the forwarding problem can never be fully
resolved. Variadic templates and rvalue references solved some of the most
pernicious issues, but even they aren't perfect.
Forwarding braced-init-lists as braced-init-lists is impossible, since they
cannot be values. You can't store them, by definition. So they can't go
into a parameter pack. My syntax doesn't change this fact, nor should it.
That's not the point of this proposal.
I think the idea of adding a first dummy argument for disambiguation
> is better because it does not invent new initialization syntaxes but
> just make one syntax work for all cases.
The problem with this solution, as covered by the proposal, is that it only
fixes the problem for one type: the type that implements the disambiguation
parameter. Which means it has to be done by everyone, everywhere.
Furthermore, different library authors will have different ideas about
different syntax. Some will prefer the first argument to disambiguate. Some
will use the last. They will use different types, thus forcing you to use a
different type name for disambiguation for different libraries. And so
forth.
The language solution is consistent and uniform for all users. It
interoperates, and is much more readable overall. It doesn't require
library authors to do anything at all.
> But it's still not enough
> bang for the buck if you ask me. This also seems like yet another hack
> that just tries to cover up funny overload resolution rules.
>
> > We as C++ programmers need to stop relying on these quick-fix
> > solutions.
>
> Including yours?
>
Language changes are anything *but* quick fixes.
On Wed, Jan 30, 2013 at 4:34 AM, Nevin Liber wrote:
> > On 29 January 2013 21:17, Nicol Bolas wrote:
> >
> >> Thinking like you're doing is what gives us nightmare library features
> >> like `std::enable_if` and other similar metaprogramming garbage. It's
> always
> >> easier to just make everyone else do more work than to fix the problem
> >> right. Yes, they work, but they're horrible to read and painful to use.
> >
> > Okay, I'll bite. What's your "obvious" solution to enable_if? The last
> > solution, Concepts, is still years in the making...
>
> Concepts really tried to kill three birds with one stone:
> - constraining templates
> - modular type checking (checking templates before instantiation)
> - concept-based overloading
>
> enable_if ist just about the first one and probably much easier to
> implement as a core language feature.
>
> Cheers!
> SG
>
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_24_14731543.1359580981423
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Wednesday, January 30, 2013 5:36:21 AM UTC-8, Sebastian Gesemann=
wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.=
8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On Wed, Jan 30, 2013 at=
4:25 AM, Nicol Bolas wrote:
<br>> Indeed, arguing against having a fix is like saying that we should=
n't allow
<br>> this to work:
<br>>
<br>> void Func(int i);
<br>> void Func(float f);
<br>>
<br>> Func(1.0); //Ambiguous call
<br>> Func((float)1.0); //Ambiguity resolved
<br>>
<br>> My proposal is conceptually no different than this.
<br>
<br>Actually, it is different. In this example you did not change the
<br>initialization syntax, but just an argument's expression. The
<br>initialization syntax and the argument expressions are two separate
<br>things.</blockquote><div><br>That's an implementation difference only; =
<i>conceptually </i>they are the same: there is an ambiguity, so you add a =
syntax construct to resolve it. Yes, one changes the argument's expression,=
but braced-init-lists aren't expressions. They will therefore have to use =
different syntax from expressions to resolve the ambiguity.<br><br>Would it=
make you feel better if it were some kind of prefix syntax of the {} rathe=
r than a syntax within the {} enclosure? Because the form of the syntax is =
personal preference; what I'm concerned with is the behavior. I choose the =
syntax I did because it doesn't cause any parsing problems with existing co=
de, thus allowing me to use special identifiers rather than new keywords or=
oddball symbols.<br><br>A prefix syntax would be much harder to include th=
e 4 use cases I outlined.<br> </div><blockquote class=3D"gmail_quote" =
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-l=
eft: 1ex;">You propose to add two additional initialization syntaxes
<br>instead of making one syntax work for more cases. It's a hack, a quick
<br>fix for odd overload resolution rules and vector<int> unfortunate=
ly
<br>relying on these odd overload resolution rules to disambiguate between
<br>two constructors merely based on the kind of initialization syntax and
<br>not the list of arguments like it probably should.</blockquote><div><br=
>The fact is, once uniform initialization shipped with the ambiguity as par=
t of it, with the ability for {} to resolve to an initializer_list construc=
tor <i>at all</i>, the damage was done. And since we can't remove that feat=
ure, our only choice is to find a way to let the user specify how <i>they</=
i> want the ambiguity resolved.<br><br>That's all I'm proposing here. It's =
not a different initialization syntax; it's a slight modification of the <i=
>same</i> initialization syntax. In every other respect, it works identical=
ly to {}.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0=
;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">Your fi=
x stops
<br>working when you have to think about how you should implment
<br>allocator<>::construct. Ideally the user of this construct functi=
on
<br>template is able to control how the object should be initialized by
<br>using appropriate arguments so that overload resolution picks the
<br>right one. You just added yet another mechanism of control that
<br>doesn't work in the contexts like allocator<>::construct unless y=
ou
<br>add special casing for {c:} and {l:} via providing construct_l and
<br>construct_c or something like this. This special casing would be
<br>viral, too. You'd need this special casing also in make_shared and
<br>emplace_back for example. But this special casing would already be
<br>possible in C++11 today without {c:} and {l:}.<br></blockquote><div><br=
>This argument is off-topic. You're talking about the problem of forwarding=
initialization intent. That's a problem that exists <i>now</i>; there's no=
way to make the called function use a set of parameters with {} syntax ins=
tead of () syntax. My proposal does not aim to fix this situation.<br><br>I=
n short, forwarding initialization intent is a problem now. It would be a p=
roblem even with this proposal. But this proposal is <i>not trying</i> to s=
olve that problem. So the fact that it's a problem is irrelevant to this di=
scussion. Yes, the proposal makes the problem slightly worse in that there =
are more forms of initialization to forward. But we already have two forms =
currently: braced-init-list vs. () syntax.<br><br>Adding variations of brac=
ed-init-lists to any such resolution will be no more difficult than resolvi=
ng the problem in the first place.<br><br>Personally, I don't think the pro=
blem can be resolved. At some level, we are going to have to accept that th=
e forwarding problem can never be fully resolved. Variadic templates and rv=
alue references solved some of the most pernicious issues, but even they ar=
en't perfect.<br><br>Forwarding braced-init-lists as braced-init-lists is i=
mpossible, since they cannot be values. You can't store them, by definition=
.. So they can't go into a parameter pack. My syntax doesn't change this fac=
t, nor should it. That's not the point of this proposal.<br><br></div><bloc=
kquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-l=
eft: 1px #ccc solid;padding-left: 1ex;">
I think the idea of adding a first dummy argument for disambiguation
<br>is better because it does not invent new initialization syntaxes but
<br>just make one syntax work for all cases.</blockquote><div><br>The probl=
em with this solution, as covered by the proposal, is that it only fixes th=
e problem for one type: the type that implements the disambiguation paramet=
er. Which means it has to be done by everyone, everywhere.<br><br>Furthermo=
re, different library authors will have different ideas about different syn=
tax. Some will prefer the first argument to disambiguate. Some will use the=
last. They will use different types, thus forcing you to use a different t=
ype name for disambiguation for different libraries. And so forth.<br><br>T=
he language solution is consistent and uniform for all users. It interopera=
tes, and is much more readable overall. It doesn't require library authors =
to do anything at all.<br> </div><blockquote class=3D"gmail_quote" sty=
le=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left=
: 1ex;">But it's still not enough
<br>bang for the buck if you ask me. This also seems like yet another hack
<br>that just tries to cover up funny overload resolution rules.
<br>
<br>> We as C++ programmers need to stop relying on these quick-fix
<br>> solutions.
<br>
<br>Including yours?<br></blockquote><div><br>Language changes are anything=
<i>but</i> quick fixes.<br><br></div><blockquote class=3D"gmail_quote" sty=
le=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left=
: 1ex;">
On Wed, Jan 30, 2013 at 4:34 AM, Nevin Liber wrote:
<br>> On 29 January 2013 21:17, Nicol Bolas wrote:
<br>>
<br>>> Thinking like you're doing is what gives us nightmare library =
features
<br>>> like `std::enable_if` and other similar metaprogramming garbag=
e. It's always
<br>>> easier to just make everyone else do more work than to fix the=
problem
<br>>> right. Yes, they work, but they're horrible to read and painfu=
l to use.
<br>>
<br>> Okay, I'll bite. What's your "obvious" solution to enable_if=
? The last
<br>> solution, Concepts, is still years in the making...
<br>
<br>Concepts really tried to kill three birds with one stone:
<br>- constraining templates
<br>- modular type checking (checking templates before instantiation)
<br>- concept-based overloading
<br>
<br>enable_if ist just about the first one and probably much easier to
<br>implement as a core language feature.
<br>
<br>Cheers!
<br>SG
<br></blockquote>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_24_14731543.1359580981423--
.
Author: DeadMG <wolfeinstein@gmail.com>
Date: Wed, 30 Jan 2013 13:47:25 -0800 (PST)
Raw View
------=_Part_71_9840790.1359582445333
Content-Type: text/plain; charset=ISO-8859-1
IYAM, the simplest way to deal with aggregates is to simply cut aggregate
initialization, and then say that aggregates have implicitly generated
explicit constructors. So that for
struct agg {
int i;
};
You could consider it as
struct agg {
agg() = default;
agg(const agg&) = default;
agg(agg&&) = default;
explicit agg(int __i = int())
: i(std::move(__i)) {}
int i;
};
This, AFAIK, should allow all existing code to continue to compile and
behave the same without changes under uniform initialization. It would also
permit more compatibility with C++03 code that uses () initialization.
At some level, we are going to have to accept that the forwarding problem
> can never be fully resolved.
It can't be without some new syntax, but it certainly could be in general
without any breaking changes. It really depends on how much you'd be
willing to "pay" in terms of new features/idioms/etc.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_71_9840790.1359582445333
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
IYAM, the simplest way to deal with aggregates is to simply cut aggregate i=
nitialization, and then say that aggregates have implicitly generated expli=
cit constructors. So that for<div><br></div><div>struct agg {<br> &nb=
sp; int i;</div><div>};</div><div><br></div><div>You could consider it as</=
div><div><br></div><div>struct agg {</div><div> agg() =3D defa=
ult;</div><div> agg(const agg&) =3D default;</div><div>&nb=
sp; agg(agg&&) =3D default;</div><div> explicit=
agg(int __i =3D int())</div><div> : i(std::move=
(__i)) {}</div><div> int i;</div><div>};</div><div><br></div><=
div>This, AFAIK, should allow all existing code to continue to compile and =
behave the same without changes under uniform initialization. It would also=
permit more compatibility with C++03 code that uses () initialization.</di=
v><div><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px=
0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); =
border-left-style: solid; padding-left: 1ex;"> At some level, we are g=
oing to have to accept that the forwarding problem can never be fully resol=
ved.</blockquote><div><br></div><div>It can't be without some new syntax, b=
ut it certainly could be in general without any breaking changes. It really=
depends on how much you'd be willing to "pay" in terms of new features/idi=
oms/etc. </div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_71_9840790.1359582445333--
.
Author: vattilah-groups@yahoo.co.uk
Date: Wed, 30 Jan 2013 23:12:02 -0800 (PST)
Raw View
------=_Part_419_23010119.1359616322442
Content-Type: text/plain; charset=ISO-8859-1
On Wednesday, 30 January 2013 21:47:25 UTC, DeadMG wrote:
>
> IYAM, the simplest way to deal with aggregates is to simply cut aggregate
> initialization, and then say that aggregates have implicitly generated
> explicit constructors.
Agree. I suggested this way to deal with aggregates as well earlier in this
thread. Moving towards treating all initialization as construction gets us
closer to one day, maybe, introducing language support for tuples (which
has been my preference since the "uniform initialization" feature was in
its infancy, and I first encountered the awkward initializer_list type with
horror). The challenge then is to define all current initialization
behaviour in terms of conversions of the built-in tuple type.
At that point, disambiguation can be done through the type system, as is
the ingrained way of doing things in C++.
Regards,
Vidar Hasfjord
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_419_23010119.1359616322442
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Wednesday, 30 January 2013 21:47:25 UTC, DeadMG wrote:<blockquote style=
=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(20=
4, 204, 204); border-left-width: 1px; border-left-style: solid;" class=3D"g=
mail_quote">IYAM, the simplest way to deal with aggregates is to simply cut=
aggregate initialization, and then say that aggregates have implicitly gen=
erated explicit constructors.</blockquote><div> </div><div>Agree. I su=
ggested this way to deal with aggregates as well earlier in this thread. Mo=
ving towards treating all initialization as construction gets us closer to =
one day, maybe, introducing language support for tuples (which has been my =
preference since the "uniform initialization" feature was in its infancy, a=
nd I first encountered the awkward initializer_list type with horror). The =
challenge then is to define all current initialization behaviour in terms o=
f conversions of the built-in tuple type.</div><div> </div><div>At tha=
t point, disambiguation can be done through the type system, as is the ingr=
ained way of doing things in C++.</div><div> </div><div>Regards,</div>=
<div>Vidar Hasfjord</div><div> </div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_419_23010119.1359616322442--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Thu, 31 Jan 2013 02:38:50 -0800 (PST)
Raw View
------=_Part_727_18883947.1359628730140
Content-Type: text/plain; charset=ISO-8859-1
On Thursday, January 31, 2013 12:50:13 AM UTC+4, Nicol Bolas wrote:
>
> On Wednesday, January 30, 2013 5:50:25 AM UTC-8, Nikolay Ivchenkov wrote:
>>
>> On Wednesday, January 30, 2013 7:05:50 AM UTC+4, Nicol Bolas wrote:
>>
>>> On Tuesday, January 29, 2013 6:28:34 AM UTC-8, Nikolay Ivchenkov wrote:
>>>>
>>>> You are suggesting two different kinds of initialization, rather than
>>>> one uniform initialization syntax (as several people already noticed).
>>>>
>>>
>>> I'm suggesting two slight variations of initialization syntax
>>>
>>
>> That sounds like "slightly pregnant". {c:} and {l:} are two different
>> syntactic constructs. Similarly, static_cast<T>(x) and const_cast<T>(x) are
>> two different syntactic constructs.
>>
>
> {c:} and {l:} are conceptually like the difference between
> static_cast<float> and static_cast<int> than static_cast and const_cast.
>
float and int aren't essential parts of the conversion syntax. They are
operands, unlike your c and l.
> They are two mechanisms that operate similarly: they modify how their
> parameter is interpreted by subsequent code. Which modification they
> perform is based on the parameter.
>
c and l are contived arguments, they don't give any capabilities. Pair {c:}
+ {l:} can be replaced with (:) + {:} so that the functionality will be the
same. Keywords static_cast and const_cast could also be considered as
contrived operands of explicit type conversion, but there is no point in
such interpretation.
so that the user can express what they're getting.
>>>
>>
>> This goal can be achieved by replacing one pseudo-uniform initialization
>> syntax with a combination of _different_ syntactic constructs. {c:} + {l:}
>> is one of possible combinations, but, IMO, it's not the best option.
>>
>
> My point is that your opinion is based on your belief that initialization
> should not be uniform,
>
I'm not even sure that "uniform" has the same meaning for us.
> The only difference is which constructors are considered; all of the other
>>> aspects of initialization (initializing aggregates, figuring out what type
>>> to use, etc) remain the same. In short, 90% of the text around such
>>> braced-init-lists in the standard will be identical; all that changes is
>>> the part of 13.3.1.7 that says which constructors are considered.
>>>
>>
>> If that's so simple, why don't you provide exact wording changes?
>>
>
> First, I never said that the wording was "simple"; I said that it was *
> localized*.
>
"*Localized*" is an abstract advantage. I saw and can imagine a lot of very
simple modifications to normative wordings, that affect several places in
the standard.
> Personally, I've never understood this notion that aggregate
>>> initialization is in any way like initializer_list initialization. It's far
>>> more like constructor syntax than initializer_lists, since aggregates don't
>>> have to contain the same types.
>>>
>>
>> ...while objects with arbitrary constructors don't have to contain any
>> sequences at all. What is common between aggregates and objects with
>> arbitrary constructors? Why should we use different syntax for built-in
>> arrays / std::array and std::vector?
>>
>> int arr[] = {c: 10, 20};
>> std::array<int, 2> a{c: 10, 20};
>> std::vector<int> v{l: 10, 20};
>>
>
> Because the user needs that specificity for objects with constructors:
>
> std::vector<int> v1{l: 10, 20};
> std::vector<int> v2{c: 10, 20};
>
> These do different things.
>
That answer is unrelated to my questions about similarity.
If I'm in a template context and I have some type T, which may or may not
> be an aggregate, I need to tell the compiler which one I mean.
>
> Thus:
>
> template<typename T>
> void Func()
> {
> T arr{l: 10, 20};
> //Do stuff with arr
> }
>
> void Func<int[2]>();
> void Func<std::array<int, 2>>();
> void Func<std::vector<int>>();
>
> Where `T` is any form of container which can be initialized with {l:}
> syntax with two elements.
>
> Your way would require that I do some std::enable_if detection and so
> forth to figure out if `T` is an aggregate and use a different codepath or
> whatever.
>
That's not so.
template<typename T>
void Func()
{
T arr = ~{10, 20};
//Do stuff with arr
}
void Func<int[2]>();
void Func<std::array<int, 2>>();
void Func<std::vector<int>>();
We already found out that simple replacement of (items...) with {c:
>> items...} is able to break a lot of existing code. You may be sure that if
>> such a change will be accepted, many people will curse the author of the
>> proposal and the committee.
>>
>
> Did we? In what case would {c:} usage for all of the currently
> constructor-based initialization break code?
>
Well, now I see why you don't understand objections. This is just because
you are not interested in thorough consideration of objections. Thus, there
are no reasons to continue the conversation with you.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_727_18883947.1359628730140
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Thursday, January 31, 2013 12:50:13 AM UTC+4, Nicol Bolas wrote:<blockqu=
ote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left=
: 1px #ccc solid;padding-left: 1ex;">On Wednesday, January 30, 2013 5:50:25=
AM UTC-8, Nikolay Ivchenkov wrote:<blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
>On Wednesday, January 30, 2013 7:05:50 AM UTC+4, Nicol Bolas wrote:<br><bl=
ockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-l=
eft:1px #ccc solid;padding-left:1ex">On Tuesday, January 29, 2013 6:28:34 A=
M UTC-8, Nikolay Ivchenkov wrote:<blockquote class=3D"gmail_quote" style=3D=
"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex">Yo=
u are suggesting two different kinds of initialization, rather than one uni=
form initialization syntax (as several people already noticed).<br></blockq=
uote><div><br>I'm suggesting two slight variations of initialization syntax=
</div></blockquote><div><br>That sounds like "slightly pregnant". {c:} and =
{l:} are two different syntactic constructs. Similarly, static_cast<T>=
;(x) and const_cast<T>(x) are two different syntactic constructs.<br>=
</div></blockquote><div><br>{c:} and {l:} are conceptually like the differe=
nce between static_cast<float> and static_cast<int> than static=
_cast and const_cast.</div></blockquote><div><br>float and int aren't essen=
tial parts of the conversion syntax. They are operands, unlike your c and l=
..<br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div> They ar=
e two mechanisms that operate similarly: they modify how their parameter is=
interpreted by subsequent code. Which modification they perform is based o=
n the parameter.<br></div></blockquote><div><br>c and l are contived argume=
nts, they don't give any capabilities. Pair {c:} + {l:} can be replaced wit=
h (:) + {:} so that the functionality will be the same. Keywords static_cas=
t and const_cast could also be considered as contrived operands of explicit=
type conversion, but there is no point in such interpretation.<br><br></di=
v><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;"><div></div><blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><blockquote class=3D"gmail_quote" style=3D"margin:0;=
margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>so that=
the user can express what they're getting.</div></blockquote><div><br>This=
goal can be achieved by replacing one pseudo-uniform initialization syntax=
with a combination of _different_ syntactic constructs. {c:} + {l:} is one=
of possible combinations, but, IMO, it's not the best option.<br></div></b=
lockquote><div><br>My point is that your opinion is based on your belief th=
at initialization should not be uniform,</div></blockquote><div><br>I'm not=
even sure that "uniform" has the same meaning for us.<br> </div><bloc=
kquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-l=
eft: 1px #ccc solid;padding-left: 1ex;"><div><blockquote style=3D"margin:0p=
x 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex" cl=
ass=3D"gmail_quote"><div><blockquote class=3D"gmail_quote" style=3D"margin:=
0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div>
The only difference is which constructors are considered; all of the=20
other aspects of initialization (initializing aggregates, figuring out=20
what type to use, etc) remain the same. In short, 90% of the text around
such braced-init-lists in the standard will be identical; all that=20
changes is the part of 13.3.1.7 that says which constructors are=20
considered.<br></div></blockquote></div><br>If that's so simple, why don't =
you provide exact wording changes?<br></blockquote><br>First, I never said =
that the wording was "simple"; I said that it was <i>localized</i>.</div></=
blockquote><div><br>"<i>Localized</i>" is an abstract advantage. I saw and =
can imagine a lot of very simple modifications to normative wordings, that =
affect several places in the standard.</div><div> </div><blockquote cl=
ass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px =
#ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"m=
argin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div=
></div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8e=
x;border-left:1px #ccc solid;padding-left:1ex"><div>Personally, I've never =
understood this notion that aggregate initialization is in any way like ini=
tializer_list initialization. It's far more like constructor syntax than in=
itializer_lists, since aggregates don't have to contain the same types.</di=
v></blockquote><div><br>...while objects with arbitrary constructors don't =
have to contain any sequences at all. What is common between aggregates and=
objects with arbitrary constructors? Why should we use different syntax fo=
r built-in arrays / std::array and std::vector?<br><br> i=
nt arr[] =3D {c: 10, 20};<br> std::array<int, 2> a{=
c: 10, 20};<br> std::vector<int> v{l: 10, 20};<br><=
/div></blockquote><div><br>Because the user needs that specificity for obje=
cts with constructors:<br><br><div style=3D"background-color:rgb(250,250,25=
0);border-color:rgb(187,187,187);border-style:solid;border-width:1px;word-w=
rap:break-word"><code><div><span style=3D"color:#000">std</span><span style=
=3D"color:#660">::</span><span style=3D"color:#000">vector</span><span styl=
e=3D"color:#080"><int></span><span style=3D"color:#000"> v1</span><sp=
an style=3D"color:#660">{</span><span style=3D"color:#000">l</span><span st=
yle=3D"color:#660">:</span><span style=3D"color:#000"> </span><span style=
=3D"color:#066">10</span><span style=3D"color:#660">,</span><span style=3D"=
color:#000"> </span><span style=3D"color:#066">20</span><span style=3D"colo=
r:#660">};</span><span style=3D"color:#000"><br>std</span><span style=3D"co=
lor:#660">::</span><span style=3D"color:#000">vector</span><span style=3D"c=
olor:#080"><int></span><span style=3D"color:#000"> v2</span><span sty=
le=3D"color:#660">{</span><span style=3D"color:#000">c</span><span style=3D=
"color:#660">:</span><span style=3D"color:#000"> </span><span style=3D"colo=
r:#066">10</span><span style=3D"color:#660">,</span><span style=3D"color:#0=
00"> </span><span style=3D"color:#066">20</span><span style=3D"color:#660">=
};</span></div></code></div><br>These do different things.<br></div></block=
quote><div><br>That answer is unrelated to my questions about similarity.<b=
r><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>If I'm in a t=
emplate context and I have some type T, which may or may not be an aggregat=
e, I need to tell the compiler which one I mean.<br><br>Thus:<br><br><div s=
tyle=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);bor=
der-style:solid;border-width:1px;word-wrap:break-word"><code><div><span sty=
le=3D"color:#008">template</span><span style=3D"color:#660"><</span><spa=
n style=3D"color:#008">typename</span><span style=3D"color:#000"> T</span><=
span style=3D"color:#660">></span><span style=3D"color:#000"><br></span>=
<span style=3D"color:#008">void</span><span style=3D"color:#000"> </span><s=
pan style=3D"color:#606">Func</span><span style=3D"color:#660">()</span><sp=
an style=3D"color:#000"><br></span><span style=3D"color:#660">{</span><span=
style=3D"color:#000"><br> T arr</span><span style=3D"color:#660">{</=
span><span style=3D"color:#000">l</span><span style=3D"color:#660">:</span>=
<span style=3D"color:#000"> </span><span style=3D"color:#066">10</span><spa=
n style=3D"color:#660">,</span><span style=3D"color:#000"> </span><span sty=
le=3D"color:#066">20</span><span style=3D"color:#660">};</span><span style=
=3D"color:#000"><br> </span><span style=3D"color:#800">//Do stuff wit=
h arr</span><span style=3D"color:#000"><br></span><span style=3D"color:#660=
">}</span><span style=3D"color:#000"><br><br></span><span style=3D"color:#0=
08">void</span><span style=3D"color:#000"> </span><span style=3D"color:#606=
">Func</span><span style=3D"color:#660"><</span><span style=3D"color:#00=
8">int</span><span style=3D"color:#660">[</span><span style=3D"color:#066">=
2</span><span style=3D"color:#660">]>();</span><span style=3D"color:#000=
"><br></span><span style=3D"color:#008">void</span><span style=3D"color:#00=
0"> </span><span style=3D"color:#606">Func</span><span style=3D"color:#660"=
><</span><span style=3D"color:#000">std</span><span style=3D"color:#660"=
>::</span><span style=3D"color:#000">array</span><span style=3D"color:#660"=
><</span><span style=3D"color:#008">int</span><span style=3D"color:#660"=
>,</span><span style=3D"color:#000"> </span><span style=3D"color:#066">2</s=
pan><span style=3D"color:#660">>>();</span><span style=3D"color:#000"=
><br></span><span style=3D"color:#008">void</span><span style=3D"color:#000=
"> </span><span style=3D"color:#606">Func</span><span style=3D"color:#660">=
<</span><span style=3D"color:#000">std</span><span style=3D"color:#660">=
::</span><span style=3D"color:#000">vector</span><span style=3D"color:#080"=
><int></span><span style=3D"color:#660">>();</span><span style=3D"=
color:#000"><br></span></div></code></div><br>Where `T` is any form of cont=
ainer which can be initialized with {l:} syntax with two elements.<br><br>Y=
our way would require that I do some std::enable_if detection and so forth =
to figure out if `T` is an aggregate and use a different codepath or whatev=
er.</div></blockquote><div><br>That's not so.<br><br> tem=
plate<typename T><br> void Func()<br> &n=
bsp; {<br> T arr =3D ~{10, 20};<b=
r> //Do stuff with arr<br> &=
nbsp; }<br><br> void Func<int[2]>();<br> =
; void Func<std::array<int, 2>>();<br> &=
nbsp; void Func<std::vector<int>>();<br><br></div><blockquote c=
lass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px=
#ccc solid;padding-left: 1ex;"><blockquote class=3D"gmail_quote" style=3D"=
margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><di=
v><div>We already found out=20
that simple replacement of (items...) with {c: items...} is able to=20
break a lot of existing code. You may be sure that if such a change will
be accepted, many people will curse the author of the proposal and the=20
committee.</div></div></blockquote><div><br>Did we? In what case would {c:}=
usage for all of the currently constructor-based initialization break code=
?<br></div></blockquote><div><br>Well, now I see why you don't understand o=
bjections. This is just because you are not interested in thorough consider=
ation of objections. Thus, there are no reasons to continue the conversatio=
n with you.</div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_727_18883947.1359628730140--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Thu, 31 Jan 2013 02:43:09 -0800 (PST)
Raw View
------=_Part_733_32226264.1359628989026
Content-Type: text/plain; charset=ISO-8859-1
On Thursday, January 31, 2013 1:47:25 AM UTC+4, DeadMG wrote:
>
> IYAM, the simplest way to deal with aggregates is to simply cut aggregate
> initialization, and then say that aggregates have implicitly generated
> explicit constructors.
How would you suggest to distinguish lvalues and rvalues?
struct X
{
std::string s1, s2;
std::unique_ptr<std::string> p;
};
int main()
{
std::string s = "string";
X x = { "text", s, std::unique_ptr<std::string>(new std::string(s))
};
}
What signature should the aggregate ctor of X have?
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_733_32226264.1359628989026
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Thursday, January 31, 2013 1:47:25 AM UTC+4, DeadMG wrote:<blockquote cl=
ass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px =
#ccc solid;padding-left: 1ex;">IYAM,
the simplest way to deal with aggregates is to simply cut aggregate=20
initialization, and then say that aggregates have implicitly generated=20
explicit constructors.</blockquote><div><br>How would you suggest to distin=
guish lvalues and rvalues?<br><br> struct X<br> &nbs=
p; {<br> std::string s1, s2=
;<br> std::unique_ptr<std::str=
ing> p;<br> };<br><br> int main()<br=
> {<br> std::st=
ring s =3D "string";<br> X x =3D =
{ "text", s, std::unique_ptr<std::string>(new std::string(s)) };<br>&=
nbsp; }<br><br>What signature should the aggregate ctor of X ha=
ve?<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_733_32226264.1359628989026--
.
Author: DeadMG <wolfeinstein@gmail.com>
Date: Thu, 31 Jan 2013 03:44:34 -0800 (PST)
Raw View
------=_Part_327_5538446.1359632674770
Content-Type: text/plain; charset=ISO-8859-1
It has one parameter for each data member which is the type of that data
member that is then forwarded to it. So in the case of X, it would be
X(std::string __s1 = std::string(), std::string __s2 = std::string(),
std::unique_ptr<std::string> __s3 = std::unique_ptr<std::string>())
: s1(std::forward<std::string>(__s1)),
s2(std::forward<std::string>(__s2)),
p(std::forward<std::unique_ptr<std::string>>(__s3)) {}
Considering, however, immovable types, perhaps it would be more accurate
(although less convenient) to specify as
X(std::string __s1)
: s1(std::forward<std::string>(s1)), s2(), p() {}
X(std::string __s1, std::string __s2)
: s1(std::forward<std::string(__s1)),
s2(std::forward<std::string>(__s2)), p() {}
This should retain the correct semantics in terms of immovable types, and
types which behave differently when value-initialized, such as int.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_327_5538446.1359632674770
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
It has one parameter for each data member which is the type of that data me=
mber that is then forwarded to it. So in the case of X, it would be<div><br=
></div><div> X(std::string __s1 =3D std::string(), std::string=
__s2 =3D std::string(), std::unique_ptr<std::string> __s3 =3D std::u=
nique_ptr<std::string>())</div><div> : s1(=
std::forward<std::string>(__s1)), s2(std::forward<std::string>(=
__s2)), p(std::forward<std::unique_ptr<std::string>>(__s3)) {}<=
/div><div><br></div><div>Considering, however, immovable types, perhaps it =
would be more accurate (although less convenient) to specify as</div><div><=
br></div><div> X(std::string __s1)</div><div> &nb=
sp; : s1(std::forward<std::string>(s1)), s2(), p() {}</div><di=
v> X(std::string __s1, std::string __s2)</div><div> &nbs=
p; : s1(std::forward<std::string(__s1)), s2(std::forward&l=
t;std::string>(__s2)), p() {}</div><div><br></div><div>This should retai=
n the correct semantics in terms of immovable types, and types which behave=
differently when value-initialized, such as int.</div><div><br></div><div>=
<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_327_5538446.1359632674770--
.
Author: Sebastian Gesemann <s.gesemann@gmail.com>
Date: Thu, 31 Jan 2013 13:26:58 +0100
Raw View
On Wed, Jan 30, 2013 at 10:23 PM, Nicol Bolas wrote:
> On Wednesday, January 30, 2013 5:36:21 AM UTC-8, Sebastian Gesemann wrote:
>> On Wed, Jan 30, 2013 at 4:25 AM, Nicol Bolas wrote:
>> > Indeed, arguing against having a fix is like saying that we shouldn't
>> > allow this to work:
>> >
>> > void Func(int i);
>> > void Func(float f);
>> >
>> > Func(1.0); //Ambiguous call
>> > Func((float)1.0); //Ambiguity resolved
>> >
>> > My proposal is conceptually no different than this.
>>
>> Actually, it is different. In this example you did not change the
>> initialization syntax, but just an argument's expression. The
>> initialization syntax and the argument expressions are two separate
>> things.
>
> That's an implementation difference only; conceptually they are the same:
> there is an ambiguity, so you add a syntax construct to resolve it. Yes, one
> changes the argument's expression, but braced-init-lists aren't expressions.
They are not expressions but its elements are expressions. However, c:
or l: are not expressions but part of your initialization syntax.
> They will therefore have to use different syntax from expressions to resolve
> the ambiguity.
I already provided a counter example to that. Here is it again:
vector<int> foo {nolist,23,42};
Here "nolist" is actually the list's first element of a special type
that would be discarded during overload resolution for constructors.
This is a truly uniform syntax: just curly braces. You can use this
syntax for every initialization and control overload resolution by
providing the appropriate arguments. Having this truly unique syntax
allows us to use plan {} in allocator<>::construct and so on.
> Would it make you feel better if it were some kind of prefix syntax of the
> {} rather than a syntax within the {} enclosure?
No. It does not make a difference. I still would not consider this an
improvement w.r.t. uniform initialization because there really isn't
anything uniform about it, if you still have to use at least two
syntaxes to be able to get any kind of inizialitazion you want.
>> You propose to add two additional initialization syntaxes
>> instead of making one syntax work for more cases. It's a hack, a quick
>> fix for odd overload resolution rules and vector<int> unfortunately
>> relying on these odd overload resolution rules to disambiguate between
>> two constructors merely based on the kind of initialization syntax and
>> not the list of arguments like it probably should.
>
> The fact is, once uniform initialization shipped with the ambiguity as part
> of it, with the ability for {} to resolve to an initializer_list constructor
> at all, the damage was done.
Yes. I agree.
> And since we can't remove that feature, our
> only choice is to find a way to let the user specify how they want the
> ambiguity resolved.
They can do this already by using () and {}. It may not be as explicit
or restrictive as you want, but we already have two syntaxes to get
every kind of initialization.
> That's all I'm proposing here. It's not a different initialization syntax;
On that we disagree. And that is why I don't consider your proposal to
be an improvement towards uniform initialization.
>> Your fix stops
>> working when you have to think about how you should implment
>> allocator<>::construct. Ideally the user of this construct function
>> template is able to control how the object should be initialized by
>> using appropriate arguments so that overload resolution picks the
>> right one. You just added yet another mechanism of control that
>> doesn't work in the contexts like allocator<>::construct unless you
>> add special casing for {c:} and {l:} via providing construct_l and
>> construct_c or something like this. This special casing would be
>> viral, too. You'd need this special casing also in make_shared and
>> emplace_back for example. But this special casing would already be
>> possible in C++11 today without {c:} and {l:}.
>
> This argument is off-topic. You're talking about the problem of forwarding
> initialization intent. That's a problem that exists now; there's no way to
> make the called function use a set of parameters with {} syntax instead of
> () syntax. My proposal does not aim to fix this situation.
You should not strive for improving C++ by adding a feature that just
fixes initialization in _some_ contexts. You should strive for
proposing something that fixes initialization in every context.
Proposing a feature that fixes only half of the problems with respect
to initialization i a kind of quick fix that you may regret later when
it gets accepted, don't you think?
> In short, forwarding initialization intent is a problem now. It would be a
> problem even with this proposal. But this proposal is not trying to solve
> that problem. So the fact that it's a problem is irrelevant to this
> discussion.
I disagree. It doesn't have to be.
> The problem with this solution, as covered by the proposal, is that it only
> fixes the problem for one type: the type that implements the disambiguation
> parameter. Which means it has to be done by everyone, everywhere.
This is not true.
> Furthermore, different library authors will have different ideas about
> different syntax.
> Some will prefer the first argument to disambiguate. Some
> will use the last. They will use different types, thus forcing you to use a
> different type name for disambiguation for different libraries. And so
> forth.
Oh, sorry, I guess I wasn't clear enough and you misunderstood. I was
not talking about a library solution. I was talking about giving the
type of "nolist" special treatment from the compiler in the following
way:
struct foo {
foo(int); // #1
foo(initializer_list<int>) // #2
};
int main() {
foo x {nolist,29}; // picks #1
foo y {17}; // picks #2
}
without a constructor every receiving a "nolist" parameter. The beauty
of it is that we actually don't have to special case this in
forwarding code since nolist is just one of the parameters. This would
be an example of a truly uniform initialization where all the
information that is used in deciding which overload it should be
resolved to is encoded in the types and value categories of the
arguments to that list which are forwardable without problems.
> Language changes are anything but quick fixes.
I hope they are not.
Cheers!
SG
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
.
Author: Mikhail Semenov <mikhailsemenov1957@gmail.com>
Date: Thu, 31 Jan 2013 13:54:19 +0000
Raw View
--e89a8f643104a5131304d495f6cc
Content-Type: text/plain; charset=ISO-8859-1
I am sorry, but doesn't it look ugly:
foo x{nolist, 29};
instead of the usual
foo x(29);
My point is, should it be as follows:
foo x(29); // call foo(int);
foo x{29}; // call foo(initializer_list<int>)
If {} are used the preference should be for the initializer list, and if ()
the "standard" constructor should be preferred.
If, on the other hand, a constructor with an initializer list is absent,
either option is possible.
In this case, things will be clear, and we will avoid an "ugly", new syntax
invention.
Mikhail.
On 31 January 2013 12:26, Sebastian Gesemann <s.gesemann@gmail.com> wrote:
> On Wed, Jan 30, 2013 at 10:23 PM, Nicol Bolas wrote:
> > On Wednesday, January 30, 2013 5:36:21 AM UTC-8, Sebastian Gesemann
> wrote:
> >> On Wed, Jan 30, 2013 at 4:25 AM, Nicol Bolas wrote:
> >> > Indeed, arguing against having a fix is like saying that we shouldn't
> >> > allow this to work:
> >> >
> >> > void Func(int i);
> >> > void Func(float f);
> >> >
> >> > Func(1.0); //Ambiguous call
> >> > Func((float)1.0); //Ambiguity resolved
> >> >
> >> > My proposal is conceptually no different than this.
> >>
> >> Actually, it is different. In this example you did not change the
> >> initialization syntax, but just an argument's expression. The
> >> initialization syntax and the argument expressions are two separate
> >> things.
> >
> > That's an implementation difference only; conceptually they are the same:
> > there is an ambiguity, so you add a syntax construct to resolve it. Yes,
> one
> > changes the argument's expression, but braced-init-lists aren't
> expressions.
>
> They are not expressions but its elements are expressions. However, c:
> or l: are not expressions but part of your initialization syntax.
>
> > They will therefore have to use different syntax from expressions to
> resolve
> > the ambiguity.
>
> I already provided a counter example to that. Here is it again:
>
> vector<int> foo {nolist,23,42};
>
> Here "nolist" is actually the list's first element of a special type
> that would be discarded during overload resolution for constructors.
> This is a truly uniform syntax: just curly braces. You can use this
> syntax for every initialization and control overload resolution by
> providing the appropriate arguments. Having this truly unique syntax
> allows us to use plan {} in allocator<>::construct and so on.
>
> > Would it make you feel better if it were some kind of prefix syntax of
> the
> > {} rather than a syntax within the {} enclosure?
>
> No. It does not make a difference. I still would not consider this an
> improvement w.r.t. uniform initialization because there really isn't
> anything uniform about it, if you still have to use at least two
> syntaxes to be able to get any kind of inizialitazion you want.
>
> >> You propose to add two additional initialization syntaxes
> >> instead of making one syntax work for more cases. It's a hack, a quick
> >> fix for odd overload resolution rules and vector<int> unfortunately
> >> relying on these odd overload resolution rules to disambiguate between
> >> two constructors merely based on the kind of initialization syntax and
> >> not the list of arguments like it probably should.
> >
> > The fact is, once uniform initialization shipped with the ambiguity as
> part
> > of it, with the ability for {} to resolve to an initializer_list
> constructor
> > at all, the damage was done.
>
> Yes. I agree.
>
> > And since we can't remove that feature, our
> > only choice is to find a way to let the user specify how they want the
> > ambiguity resolved.
>
> They can do this already by using () and {}. It may not be as explicit
> or restrictive as you want, but we already have two syntaxes to get
> every kind of initialization.
>
> > That's all I'm proposing here. It's not a different initialization
> syntax;
>
> On that we disagree. And that is why I don't consider your proposal to
> be an improvement towards uniform initialization.
>
> >> Your fix stops
> >> working when you have to think about how you should implment
> >> allocator<>::construct. Ideally the user of this construct function
> >> template is able to control how the object should be initialized by
> >> using appropriate arguments so that overload resolution picks the
> >> right one. You just added yet another mechanism of control that
> >> doesn't work in the contexts like allocator<>::construct unless you
> >> add special casing for {c:} and {l:} via providing construct_l and
> >> construct_c or something like this. This special casing would be
> >> viral, too. You'd need this special casing also in make_shared and
> >> emplace_back for example. But this special casing would already be
> >> possible in C++11 today without {c:} and {l:}.
> >
> > This argument is off-topic. You're talking about the problem of
> forwarding
> > initialization intent. That's a problem that exists now; there's no way
> to
> > make the called function use a set of parameters with {} syntax instead
> of
> > () syntax. My proposal does not aim to fix this situation.
>
> You should not strive for improving C++ by adding a feature that just
> fixes initialization in _some_ contexts. You should strive for
> proposing something that fixes initialization in every context.
> Proposing a feature that fixes only half of the problems with respect
> to initialization i a kind of quick fix that you may regret later when
> it gets accepted, don't you think?
>
> > In short, forwarding initialization intent is a problem now. It would be
> a
> > problem even with this proposal. But this proposal is not trying to solve
> > that problem. So the fact that it's a problem is irrelevant to this
> > discussion.
>
> I disagree. It doesn't have to be.
>
> > The problem with this solution, as covered by the proposal, is that it
> only
> > fixes the problem for one type: the type that implements the
> disambiguation
> > parameter. Which means it has to be done by everyone, everywhere.
>
> This is not true.
>
> > Furthermore, different library authors will have different ideas about
> > different syntax.
> > Some will prefer the first argument to disambiguate. Some
> > will use the last. They will use different types, thus forcing you to
> use a
> > different type name for disambiguation for different libraries. And so
> > forth.
>
> Oh, sorry, I guess I wasn't clear enough and you misunderstood. I was
> not talking about a library solution. I was talking about giving the
> type of "nolist" special treatment from the compiler in the following
> way:
>
> struct foo {
> foo(int); // #1
> foo(initializer_list<int>) // #2
> };
>
> int main() {
> foo x {nolist,29}; // picks #1
> foo y {17}; // picks #2
> }
>
> without a constructor every receiving a "nolist" parameter. The beauty
> of it is that we actually don't have to special case this in
> forwarding code since nolist is just one of the parameters. This would
> be an example of a truly uniform initialization where all the
> information that is used in deciding which overload it should be
> resolved to is encoded in the types and value categories of the
> arguments to that list which are forwardable without problems.
>
> > Language changes are anything but quick fixes.
>
> I hope they are not.
>
>
> Cheers!
> SG
>
> --
>
> ---
> 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.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
>
>
>
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
--e89a8f643104a5131304d495f6cc
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div>I am sorry, but doesn't it look ugly: </div>
<div>foo x{nolist, 29}; </div>
<div>instead of the usual </div>
<div>foo x(29);</div>
<div>=A0</div>
<div>My point is, should it be as follows:</div>
<div>foo x(29); // call foo(int);</div>
<div>foo x{29}; // call foo(initializer_list<int>) </div>
<div>=A0</div>
<div>If {} are used the preference should be for the initializer list, and =
if () the "standard" constructor should be preferred.</div>
<div>If, on the other hand, a constructor with an initializer list is absen=
t, either option is possible.</div>
<div>In this case, things will be clear, and we will avoid an "ugly&qu=
ot;, new syntax invention.</div>
<div>=A0</div>
<div>Mikhail.<br></div>
<div class=3D"gmail_quote">On 31 January 2013 12:26, Sebastian Gesemann <sp=
an dir=3D"ltr"><<a href=3D"mailto:s.gesemann@gmail.com" target=3D"_blank=
">s.gesemann@gmail.com</a>></span> wrote:<br>
<blockquote style=3D"BORDER-LEFT:#ccc 1px solid;MARGIN:0px 0px 0px 0.8ex;PA=
DDING-LEFT:1ex" class=3D"gmail_quote">
<div class=3D"im">On Wed, Jan 30, 2013 at 10:23 PM, Nicol Bolas wrote:<br>&=
gt; On Wednesday, January 30, 2013 5:36:21 AM UTC-8, Sebastian Gesemann wro=
te:<br>>> On Wed, Jan 30, 2013 at 4:25 AM, Nicol Bolas wrote:<br>>=
> > Indeed, arguing against having a fix is like saying that we shoul=
dn't<br>
>> > allow this to work:<br>>> ><br>>> > =A0 voi=
d Func(int i);<br>>> > =A0 void Func(float f);<br>>> ><br=
>>> > Func(1.0); //Ambiguous call<br>>> > Func((float)1.0=
); //Ambiguity resolved<br>
>> ><br>>> > My proposal is conceptually no different tha=
n this.<br>>><br>>> Actually, it is different. In this example =
you did not change the<br>>> initialization syntax, but just an argum=
ent's expression. The<br>
>> initialization syntax and the argument expressions are two separat=
e<br>>> things.<br>><br>> That's an implementation differen=
ce only; conceptually they are the same:<br>> there is an ambiguity, so =
you add a syntax construct to resolve it. Yes, one<br>
> changes the argument's expression, but braced-init-lists aren'=
t expressions.<br><br></div>They are not expressions but its elements are e=
xpressions. However, c:<br>or l: are not expressions but part of your initi=
alization syntax.<br>
<div class=3D"im"><br>> They will therefore have to use different syntax=
from expressions to resolve<br>> the ambiguity.<br><br></div>I already =
provided a counter example to that. Here is it again:<br><br>=A0 =A0vector&=
lt;int> foo {nolist,23,42};<br>
<br>Here "nolist" is actually the list's first element of a s=
pecial type<br>that would be discarded during overload resolution for const=
ructors.<br>This is a truly uniform syntax: just curly braces. You can use =
this<br>
syntax for every initialization and control overload resolution by<br>provi=
ding the appropriate arguments. Having this truly unique syntax<br>allows u=
s to use plan {} in allocator<>::construct and so on.<br>
<div class=3D"im"><br>> Would it make you feel better if it were some ki=
nd of prefix syntax of the<br>> {} rather than a syntax within the {} en=
closure?<br><br></div>No. It does not make a difference. I still would not =
consider this an<br>
improvement w.r.t. uniform initialization because there really isn't<br=
>anything uniform about it, if you still have to use at least two<br>syntax=
es to be able to get any kind of inizialitazion you want.<br>
<div class=3D"im"><br>>> You propose to add two additional initializa=
tion syntaxes<br>>> instead of making one syntax work for more cases.=
It's a hack, a quick<br>>> fix for odd overload resolution rules=
and vector<int> unfortunately<br>
>> relying on these odd overload resolution rules to disambiguate bet=
ween<br>>> two constructors merely based on the kind of initializatio=
n syntax and<br>>> not the list of arguments like it probably should.=
<br>
><br>> The fact is, once uniform initialization shipped with the ambi=
guity as part<br>> of it, with the ability for {} to resolve to an initi=
alizer_list constructor<br>> at all, the damage was done.<br><br></div>
Yes. I agree.<br>
<div class=3D"im"><br>> And since we can't remove that feature, our<=
br>> only choice is to find a way to let the user specify how they want =
the<br>> ambiguity resolved.<br><br></div>They can do this already by us=
ing () and {}. It may not be as explicit<br>
or restrictive as you want, but we already have two syntaxes to get<br>ever=
y kind of initialization.<br>
<div class=3D"im"><br>> That's all I'm proposing here. It's =
not a different initialization syntax;<br><br></div>On that we disagree. An=
d that is why I don't consider your proposal to<br>be an improvement to=
wards uniform initialization.<br>
<div class=3D"im"><br>>> Your fix stops<br>>> working when you =
have to think about how you should implment<br>>> allocator<>::=
construct. Ideally the user of this construct function<br>>> template=
is able to control how the object should be initialized by<br>
>> using appropriate arguments so that overload resolution picks the<=
br>>> right one. You just added yet another mechanism of control that=
<br>>> doesn't work in the contexts like allocator<>::const=
ruct unless you<br>
>> add special casing for {c:} and {l:} via providing construct_l and=
<br>>> construct_c or something like this. This special casing would =
be<br>>> viral, too. You'd need this special casing also in make_=
shared and<br>
>> emplace_back for example. But this special casing would already be=
<br>>> possible in C++11 today without {c:} and {l:}.<br>><br>>=
This argument is off-topic. You're talking about the problem of forwar=
ding<br>
> initialization intent. That's a problem that exists now; there'=
;s no way to<br>> make the called function use a set of parameters with =
{} syntax instead of<br>> () syntax. My proposal does not aim to fix thi=
s situation.<br>
<br></div>You should not strive for improving C++ by adding a feature that =
just<br>fixes initialization in _some_ contexts. You should strive for<br>p=
roposing something that fixes initialization in every context.<br>Proposing=
a feature that fixes only half of the problems with respect<br>
to initialization i a kind of quick fix that you may regret later when<br>i=
t gets accepted, don't you think?<br>
<div class=3D"im"><br>> In short, forwarding initialization intent is a =
problem now. It would be a<br>> problem even with this proposal. But thi=
s proposal is not trying to solve<br>> that problem. So the fact that it=
's a problem is irrelevant to this<br>
> discussion.<br><br></div>I disagree. It doesn't have to be.<br>
<div class=3D"im"><br>> The problem with this solution, as covered by th=
e proposal, is that it only<br>> fixes the problem for one type: the typ=
e that implements the disambiguation<br>> parameter. Which means it has =
to be done by everyone, everywhere.<br>
<br></div>This is not true.<br>
<div class=3D"im"><br>> Furthermore, different library authors will have=
different ideas about<br>> different syntax.<br>> Some will prefer t=
he first argument to disambiguate. Some<br>> will use the last. They wil=
l use different types, thus forcing you to use a<br>
> different type name for disambiguation for different libraries. And so=
<br>> forth.<br><br></div>Oh, sorry, I guess I wasn't clear enough a=
nd you misunderstood. I was<br>not talking about a library solution. I was =
talking about giving the<br>
type of "nolist" special treatment from the compiler in the follo=
wing<br>way:<br><br>=A0 struct foo {<br>=A0 =A0 foo(int); // #1<br>=A0 =A0 =
foo(initializer_list<int>) // #2<br>=A0 };<br><br>=A0 int main() {<br=
>=A0 =A0 foo x {nolist,29}; // picks #1<br>
=A0 =A0 foo y {17}; // picks #2<br>=A0 }<br><br>without a constructor every=
receiving a "nolist" parameter. The beauty<br>of it is that we a=
ctually don't have to special case this in<br>forwarding code since nol=
ist is just one of the parameters. This would<br>
be an example of a truly uniform initialization where all the<br>informatio=
n that is used in deciding which overload it should be<br>resolved to is en=
coded in the types and value categories of the<br>arguments to that list wh=
ich are forwardable without problems.<br>
<div class=3D"im"><br>> Language changes are anything but quick fixes.<b=
r><br></div>I hope they are not.<br>
<div class=3D"HOEnZb">
<div class=3D"h5"><br><br>Cheers!<br>SG<br><br>--<br><br>---<br>You receive=
d this message because you are subscribed to the Google Groups "ISO C+=
+ Standard - Future Proposals" group.<br>To unsubscribe from this grou=
p and stop receiving emails from it, send an email to <a href=3D"mailto:std=
-proposals%2Bunsubscribe@isocpp.org">std-proposals+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>Visit this group at <a href=3D"http:=
//groups.google.com/a/isocpp.org/group/std-proposals/?hl=3Den" target=3D"_b=
lank">http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=3Den</a=
>.<br>
<br><br></div></div></blockquote></div><br>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
--e89a8f643104a5131304d495f6cc--
.
Author: Arthur Tchaikovsky <atch.cpp@gmail.com>
Date: Thu, 31 Jan 2013 13:56:31 +0000
Raw View
Couldn't agree more with Mikhail
On 1/31/13, Mikhail Semenov <mikhailsemenov1957@gmail.com> wrote:
> I am sorry, but doesn't it look ugly:
> foo x{nolist, 29};
> instead of the usual
> foo x(29);
>
> My point is, should it be as follows:
> foo x(29); // call foo(int);
> foo x{29}; // call foo(initializer_list<int>)
>
> If {} are used the preference should be for the initializer list, and if ()
> the "standard" constructor should be preferred.
> If, on the other hand, a constructor with an initializer list is absent,
> either option is possible.
> In this case, things will be clear, and we will avoid an "ugly", new syntax
> invention.
>
> Mikhail.
> On 31 January 2013 12:26, Sebastian Gesemann <s.gesemann@gmail.com> wrote:
>
>> On Wed, Jan 30, 2013 at 10:23 PM, Nicol Bolas wrote:
>> > On Wednesday, January 30, 2013 5:36:21 AM UTC-8, Sebastian Gesemann
>> wrote:
>> >> On Wed, Jan 30, 2013 at 4:25 AM, Nicol Bolas wrote:
>> >> > Indeed, arguing against having a fix is like saying that we
>> >> > shouldn't
>> >> > allow this to work:
>> >> >
>> >> > void Func(int i);
>> >> > void Func(float f);
>> >> >
>> >> > Func(1.0); //Ambiguous call
>> >> > Func((float)1.0); //Ambiguity resolved
>> >> >
>> >> > My proposal is conceptually no different than this.
>> >>
>> >> Actually, it is different. In this example you did not change the
>> >> initialization syntax, but just an argument's expression. The
>> >> initialization syntax and the argument expressions are two separate
>> >> things.
>> >
>> > That's an implementation difference only; conceptually they are the
>> > same:
>> > there is an ambiguity, so you add a syntax construct to resolve it.
>> > Yes,
>> one
>> > changes the argument's expression, but braced-init-lists aren't
>> expressions.
>>
>> They are not expressions but its elements are expressions. However, c:
>> or l: are not expressions but part of your initialization syntax.
>>
>> > They will therefore have to use different syntax from expressions to
>> resolve
>> > the ambiguity.
>>
>> I already provided a counter example to that. Here is it again:
>>
>> vector<int> foo {nolist,23,42};
>>
>> Here "nolist" is actually the list's first element of a special type
>> that would be discarded during overload resolution for constructors.
>> This is a truly uniform syntax: just curly braces. You can use this
>> syntax for every initialization and control overload resolution by
>> providing the appropriate arguments. Having this truly unique syntax
>> allows us to use plan {} in allocator<>::construct and so on.
>>
>> > Would it make you feel better if it were some kind of prefix syntax of
>> the
>> > {} rather than a syntax within the {} enclosure?
>>
>> No. It does not make a difference. I still would not consider this an
>> improvement w.r.t. uniform initialization because there really isn't
>> anything uniform about it, if you still have to use at least two
>> syntaxes to be able to get any kind of inizialitazion you want.
>>
>> >> You propose to add two additional initialization syntaxes
>> >> instead of making one syntax work for more cases. It's a hack, a quick
>> >> fix for odd overload resolution rules and vector<int> unfortunately
>> >> relying on these odd overload resolution rules to disambiguate between
>> >> two constructors merely based on the kind of initialization syntax and
>> >> not the list of arguments like it probably should.
>> >
>> > The fact is, once uniform initialization shipped with the ambiguity as
>> part
>> > of it, with the ability for {} to resolve to an initializer_list
>> constructor
>> > at all, the damage was done.
>>
>> Yes. I agree.
>>
>> > And since we can't remove that feature, our
>> > only choice is to find a way to let the user specify how they want the
>> > ambiguity resolved.
>>
>> They can do this already by using () and {}. It may not be as explicit
>> or restrictive as you want, but we already have two syntaxes to get
>> every kind of initialization.
>>
>> > That's all I'm proposing here. It's not a different initialization
>> syntax;
>>
>> On that we disagree. And that is why I don't consider your proposal to
>> be an improvement towards uniform initialization.
>>
>> >> Your fix stops
>> >> working when you have to think about how you should implment
>> >> allocator<>::construct. Ideally the user of this construct function
>> >> template is able to control how the object should be initialized by
>> >> using appropriate arguments so that overload resolution picks the
>> >> right one. You just added yet another mechanism of control that
>> >> doesn't work in the contexts like allocator<>::construct unless you
>> >> add special casing for {c:} and {l:} via providing construct_l and
>> >> construct_c or something like this. This special casing would be
>> >> viral, too. You'd need this special casing also in make_shared and
>> >> emplace_back for example. But this special casing would already be
>> >> possible in C++11 today without {c:} and {l:}.
>> >
>> > This argument is off-topic. You're talking about the problem of
>> forwarding
>> > initialization intent. That's a problem that exists now; there's no way
>> to
>> > make the called function use a set of parameters with {} syntax instead
>> of
>> > () syntax. My proposal does not aim to fix this situation.
>>
>> You should not strive for improving C++ by adding a feature that just
>> fixes initialization in _some_ contexts. You should strive for
>> proposing something that fixes initialization in every context.
>> Proposing a feature that fixes only half of the problems with respect
>> to initialization i a kind of quick fix that you may regret later when
>> it gets accepted, don't you think?
>>
>> > In short, forwarding initialization intent is a problem now. It would
>> > be
>> a
>> > problem even with this proposal. But this proposal is not trying to
>> > solve
>> > that problem. So the fact that it's a problem is irrelevant to this
>> > discussion.
>>
>> I disagree. It doesn't have to be.
>>
>> > The problem with this solution, as covered by the proposal, is that it
>> only
>> > fixes the problem for one type: the type that implements the
>> disambiguation
>> > parameter. Which means it has to be done by everyone, everywhere.
>>
>> This is not true.
>>
>> > Furthermore, different library authors will have different ideas about
>> > different syntax.
>> > Some will prefer the first argument to disambiguate. Some
>> > will use the last. They will use different types, thus forcing you to
>> use a
>> > different type name for disambiguation for different libraries. And so
>> > forth.
>>
>> Oh, sorry, I guess I wasn't clear enough and you misunderstood. I was
>> not talking about a library solution. I was talking about giving the
>> type of "nolist" special treatment from the compiler in the following
>> way:
>>
>> struct foo {
>> foo(int); // #1
>> foo(initializer_list<int>) // #2
>> };
>>
>> int main() {
>> foo x {nolist,29}; // picks #1
>> foo y {17}; // picks #2
>> }
>>
>> without a constructor every receiving a "nolist" parameter. The beauty
>> of it is that we actually don't have to special case this in
>> forwarding code since nolist is just one of the parameters. This would
>> be an example of a truly uniform initialization where all the
>> information that is used in deciding which overload it should be
>> resolved to is encoded in the types and value categories of the
>> arguments to that list which are forwardable without problems.
>>
>> > Language changes are anything but quick fixes.
>>
>> I hope they are not.
>>
>>
>> Cheers!
>> SG
>>
>> --
>>
>> ---
>> 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.
>> Visit this group at
>> http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
>>
>>
>>
>
> --
>
> ---
> 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.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
>
>
>
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Thu, 31 Jan 2013 06:19:03 -0800 (PST)
Raw View
------=_Part_492_19316774.1359641943251
Content-Type: text/plain; charset=ISO-8859-1
On Thursday, January 31, 2013 3:44:34 PM UTC+4, DeadMG wrote:
>
> It has one parameter for each data member which is the type of that data
> member that is then forwarded to it. So in the case of X, it would be
>
> X(std::string __s1 = std::string(), std::string __s2 = std::string(),
> std::unique_ptr<std::string> __s3 = std::unique_ptr<std::string>())
> : s1(std::forward<std::string>(__s1)),
> s2(std::forward<std::string>(__s2)),
> p(std::forward<std::unique_ptr<std::string>>(__s3)) {}
>
> Considering, however, immovable types, perhaps it would be more accurate
> (although less convenient) to specify as
>
> X(std::string __s1)
> : s1(std::forward<std::string>(s1)), s2(), p() {}
> X(std::string __s1, std::string __s2)
> : s1(std::forward<std::string(__s1)),
> s2(std::forward<std::string>(__s2)), p() {}
>
> This should retain the correct semantics in terms of immovable types, and
> types which behave differently when value-initialized, such as int.
>
Is that more simple than just defining initialization
AggregateType x(items...);
to be equivalent to
AggregateType x{items...};
? (Note that I don't suggest to change the rules so)
And how about efficiency? Your two-step initialization of members is
potentially less efficient than one-step initialization that takes place in
an aggregate initialization.
Finally, AggregateType(x) and AggregateType{x} may have different meaning -
see example below:
#include <cstddef>
#include <iostream>
#include <string>
#include <utility>
#define FORWARD(x) static_cast<decltype(x) &&>(x)
template <class T1, class T2>
struct P
{
template <class U1, class U2>
P(U1 &&u1, U2 &&u2) :
p(FORWARD(u1), FORWARD(u2)) {}
template <class T>
operator T() const
{ return {p.first, p.second}; }
std::pair<T1, T2> p;
};
struct A
{
std::string s;
std::size_t n;
};
int main()
{
P<std::string, std::size_t> p("whole", 1u);
A a1(p);
A a2{p};
std::cout << a1.s << " " << a1.n << std::endl;
std::cout << a2.s << " " << a2.n << std::endl;
}
http://liveworkspace.org/code/1MU15f$0
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_492_19316774.1359641943251
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Thursday, January 31, 2013 3:44:34 PM UTC+4, DeadMG wrote:<blockquote cl=
ass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px =
#ccc solid;padding-left: 1ex;">It has one parameter for each data member wh=
ich is the type of that data member that is then forwarded to it. So in the=
case of X, it would be<div><br></div><div> X(std::string __s1=
=3D std::string(), std::string __s2 =3D std::string(), std::unique_ptr<=
std::string> __s3 =3D std::unique_ptr<std::string>()<wbr>)</div><d=
iv> : s1(std::forward<std::string>(_<wbr>_=
s1)), s2(std::forward<std::string>(_<wbr>_s2)), p(std::forward<std=
::unique_<wbr>ptr<std::string>>(__s3)) {}</div><div><br></div><div=
>Considering, however, immovable types, perhaps it would be more accurate (=
although less convenient) to specify as</div><div><br></div><div> &nb=
sp; X(std::string __s1)</div><div> : s1(std::for=
ward<std::string>(<wbr>s1)), s2(), p() {}</div><div> X(s=
td::string __s1, std::string __s2)</div><div> : =
s1(std::forward<std::string(__<wbr>s1)), s2(std::forward<std::string&=
gt;(_<wbr>_s2)), p() {}</div><div><br></div><div>This should retain the cor=
rect semantics in terms of immovable types, and types which behave differen=
tly when value-initialized, such as int.</div></blockquote><div><br>Is that=
more simple than just defining initialization<br><br> Ag=
gregateType x(items...);<br><br>to be equivalent to<br><br> &nbs=
p; AggregateType x{items...};<br><br>? (Note that I don't suggest to change=
the rules so)<br><br>And how about efficiency? Your two-step initializatio=
n of members is potentially less efficient than one-step initialization tha=
t takes place in an aggregate initialization.<br><br>Finally, AggregateType=
(x) and AggregateType{x} may have different meaning - see example below:<br=
><br> #include <cstddef><br> #inc=
lude <iostream><br> #include <string><br>&nbs=
p; #include <utility><br><br> #define F=
ORWARD(x) static_cast<decltype(x) &&>(x)<br><br> &=
nbsp; template <class T1, class T2><br> =
struct P<br> {<br> &n=
bsp; template <class U1, class U2><br> &=
nbsp; P(U1 &&u1, U2 &=
&u2) :<br> &=
nbsp; p(FORWARD(u1), FORWARD(u2)) {}<br><br> &=
nbsp; template <class T><br>  =
; operator T() const<=
br> =
{ return {p.first, p.second}; }<br><br>  =
; std::pair<T1, T2> p;<br> =
};<br><br> struct A<br> {<br> &nbs=
p; std::string s;<br> =
std::size_t n;<br> };<br><br> &nb=
sp; int main()<br> {<br> &nb=
sp; P<std::string, std::size_t> p("whole", 1u);<br> =
A a1(p);<br> &n=
bsp; A a2{p};<br> std=
::cout << a1.s << " " << a1.n << std::endl;<br>&nbs=
p; std::cout << a2.s << " "=
<< a2.n << std::endl;<br> }<br><br>http://li=
veworkspace.org/code/1MU15f$0<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_492_19316774.1359641943251--
.
Author: Sebastian Gesemann <s.gesemann@gmail.com>
Date: Thu, 31 Jan 2013 15:41:20 +0100
Raw View
On Thu, Jan 31, 2013 at 2:54 PM, Mikhail Semenov wrote:
> I am sorry, but doesn't it look ugly:
> foo x{nolist, 29};
> instead of the usual
> foo x(29);
Nobody would force you to write
foo x {nolist,29};
instead of
foo x (29);
You could still write the latter if you want.
The point of "nolist" is to make the {}-syntax usable for any kind of
initialization you would want. And being explicit about not wanting to
use a possibly existing initializer_list constructor is not such a bad
thing.
How would you implement an allocator's construct function template?
new(ptr) T(forward<Args>(args)...); // #1
new(ptr) T{forward<Args>(args)...}; // #2
With #1 you can't initialize aggregates and picking the
initializer_list constructor of a vector<int> requires you to
explicitly pass a std::initializer_list object. With #2 and
T=vector<int> you can't initialize the vector to a certain size.
I argue that this problem exits because of the syntax-dependent
overload resolution rules for initialization.
I don't know what "uniform initialization syntax" means to you, but to
me it means that there is one syntax that is applicable in every
situation to do whatever you like.
Things are not perfect but I'm actually not proposing any new feature
here. It was just a counter example to one of Nicol's statements.
Personally, I don't like adding new special rules as a work around for
another already existing special rule like {} preferring initializer
list constructors.
I guess the only suggesten I'm making here is that people think hard
before creating many constructor overloads for their own classes and
learn to live with imperfections like not being able to easily invoke
a std::initializer_list constructor using emplace or make_shared.
I'd like to mention that IIRC a commitee member hinted at removing the
irregularity between auto and function template argument deduction.
You all probably know that
auto x = {1,2,3,5,8};
makes x an initializer_list<int> and that this currently only works
for auto. If it could be made to work for templates as well, we can at
least get
make_shared<vector<int>>({1,2,3,5,8})
to work. It won't work with nested lists, though, as far as I can tell.
Cheers!
SG
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
.
Author: Mikhail Semenov <mikhailsemenov1957@gmail.com>
Date: Thu, 31 Jan 2013 14:53:59 +0000
Raw View
--e89a8fb1fac808443b04d496cc24
Content-Type: text/plain; charset=ISO-8859-1
There still cane be a solution: allow conversion to a vector or any
collection. But if there is an explicit contructor with the same number of
parameter, it should be selected when () are used; and when you use {} the
vector (or whatever collection) should be converted to initializer list (if
initializer list is present).
On 31 January 2013 14:41, Sebastian Gesemann <s.gesemann@gmail.com> wrote:
> On Thu, Jan 31, 2013 at 2:54 PM, Mikhail Semenov wrote:
> > I am sorry, but doesn't it look ugly:
> > foo x{nolist, 29};
> > instead of the usual
> > foo x(29);
>
> Nobody would force you to write
>
> foo x {nolist,29};
>
> instead of
>
> foo x (29);
>
> You could still write the latter if you want.
>
> The point of "nolist" is to make the {}-syntax usable for any kind of
> initialization you would want. And being explicit about not wanting to
> use a possibly existing initializer_list constructor is not such a bad
> thing.
>
> How would you implement an allocator's construct function template?
>
> new(ptr) T(forward<Args>(args)...); // #1
> new(ptr) T{forward<Args>(args)...}; // #2
>
> With #1 you can't initialize aggregates and picking the
> initializer_list constructor of a vector<int> requires you to
> explicitly pass a std::initializer_list object. With #2 and
> T=vector<int> you can't initialize the vector to a certain size.
>
> I argue that this problem exits because of the syntax-dependent
> overload resolution rules for initialization.
>
> I don't know what "uniform initialization syntax" means to you, but to
> me it means that there is one syntax that is applicable in every
> situation to do whatever you like.
>
> Things are not perfect but I'm actually not proposing any new feature
> here. It was just a counter example to one of Nicol's statements.
> Personally, I don't like adding new special rules as a work around for
> another already existing special rule like {} preferring initializer
> list constructors.
>
> I guess the only suggesten I'm making here is that people think hard
> before creating many constructor overloads for their own classes and
> learn to live with imperfections like not being able to easily invoke
> a std::initializer_list constructor using emplace or make_shared.
>
> I'd like to mention that IIRC a commitee member hinted at removing the
> irregularity between auto and function template argument deduction.
> You all probably know that
>
> auto x = {1,2,3,5,8};
>
> makes x an initializer_list<int> and that this currently only works
> for auto. If it could be made to work for templates as well, we can at
> least get
>
> make_shared<vector<int>>({1,2,3,5,8})
>
> to work. It won't work with nested lists, though, as far as I can tell.
>
>
> Cheers!
> SG
>
> --
>
> ---
> 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.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
>
>
>
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
--e89a8fb1fac808443b04d496cc24
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
There still cane be a solution: allow conversion to a vector or any collect=
ion. But if there is an explicit contructor with the same number of paramet=
er, it should be selected when () are used; and when you use {} the vector =
(or whatever collection) should be converted to initializer list (if initia=
lizer list is present).<br>
<br>
<div class=3D"gmail_quote">On 31 January 2013 14:41, Sebastian Gesemann <sp=
an dir=3D"ltr"><<a href=3D"mailto:s.gesemann@gmail.com" target=3D"_blank=
">s.gesemann@gmail.com</a>></span> wrote:<br>
<blockquote style=3D"BORDER-LEFT:#ccc 1px solid;MARGIN:0px 0px 0px 0.8ex;PA=
DDING-LEFT:1ex" class=3D"gmail_quote">
<div class=3D"im">On Thu, Jan 31, 2013 at 2:54 PM, Mikhail Semenov wrote:<b=
r>> I am sorry, but doesn't it look ugly:<br>> foo x{nolist, 29};=
<br>> instead of the usual<br>> foo x(29);<br><br></div>Nobody would =
force you to write<br>
<br>=A0 =A0 =A0 foo x {nolist,29};<br><br>instead of<br><br>=A0 =A0 =A0 foo=
x (29);<br><br>You could still write the latter if you want.<br><br>The po=
int of "nolist" is to make the {}-syntax usable for any kind of<b=
r>initialization you would want. And being explicit about not wanting to<br=
>
use a possibly existing initializer_list constructor is not such a bad<br>t=
hing.<br><br>How would you implement an allocator's construct function =
template?<br><br>=A0 =A0 =A0 new(ptr) T(forward<Args>(args)...); // #=
1<br>
=A0 =A0 =A0 new(ptr) T{forward<Args>(args)...}; // #2<br><br>With #1 =
you can't initialize aggregates and picking the<br>initializer_list con=
structor of a vector<int> requires you to<br>explicitly pass a std::i=
nitializer_list object. With #2 and<br>
T=3Dvector<int> you can't initialize the vector to a certain size=
..<br><br>I argue that this problem exits because of the syntax-dependent<br=
>overload resolution rules for initialization.<br><br>I don't know what=
"uniform initialization syntax" means to you, but to<br>
me it means that there is one syntax that is applicable in every<br>situati=
on to do whatever you like.<br><br>Things are not perfect but I'm actua=
lly not proposing any new feature<br>here. It was just a counter example to=
one of Nicol's statements.<br>
Personally, I don't like adding new special rules as a work around for<=
br>another already existing special rule like {} preferring initializer<br>=
list constructors.<br><br>I guess the only suggesten I'm making here is=
that people think hard<br>
before creating many constructor overloads for their own classes and<br>lea=
rn to live with imperfections like not being able to easily invoke<br>a std=
::initializer_list constructor using emplace or make_shared.<br><br>I'd=
like to mention that IIRC a commitee member hinted at removing the<br>
irregularity between auto and function template argument deduction.<br>You =
all probably know that<br><br>=A0 =A0auto x =3D {1,2,3,5,8};<br><br>makes x=
an initializer_list<int> and that this currently only works<br>for a=
uto. If it could be made to work for templates as well, we can at<br>
least get<br><br>=A0 =A0make_shared<vector<int>>({1,2,3,5,8})<b=
r><br>to work. It won't work with nested lists, though, as far as I can=
tell.<br>
<div class=3D"HOEnZb">
<div class=3D"h5"><br><br>Cheers!<br>SG<br><br>--<br><br>---<br>You receive=
d this message because you are subscribed to the Google Groups "ISO C+=
+ Standard - Future Proposals" group.<br>To unsubscribe from this grou=
p and stop receiving emails from it, send an email to <a href=3D"mailto:std=
-proposals%2Bunsubscribe@isocpp.org">std-proposals+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>Visit this group at <a href=3D"http:=
//groups.google.com/a/isocpp.org/group/std-proposals/?hl=3Den" target=3D"_b=
lank">http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=3Den</a=
>.<br>
<br><br></div></div></blockquote></div><br>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
--e89a8fb1fac808443b04d496cc24--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Thu, 31 Jan 2013 08:51:25 -0800 (PST)
Raw View
------=_Part_843_22407624.1359651085781
Content-Type: text/plain; charset=ISO-8859-1
On Thursday, January 31, 2013 4:26:58 AM UTC-8, Sebastian Gesemann wrote:
>
> On Wed, Jan 30, 2013 at 10:23 PM, Nicol Bolas wrote:
> > On Wednesday, January 30, 2013 5:36:21 AM UTC-8, Sebastian Gesemann
> wrote
>
> Furthermore, different library authors will have different ideas about
> > different syntax.
> > Some will prefer the first argument to disambiguate. Some
> > will use the last. They will use different types, thus forcing you to
> use a
> > different type name for disambiguation for different libraries. And so
> > forth.
>
> Oh, sorry, I guess I wasn't clear enough and you misunderstood. I was
> not talking about a library solution. I was talking about giving the
> type of "nolist" special treatment from the compiler in the following
> way:
>
> struct foo {
> foo(int); // #1
> foo(initializer_list<int>) // #2
> };
>
> int main() {
> foo x {nolist,29}; // picks #1
> foo y {17}; // picks #2
> }
>
> without a constructor every receiving a "nolist" parameter. The beauty
> of it is that we actually don't have to special case this in
> forwarding code since nolist is just one of the parameters. This would
> be an example of a truly uniform initialization where all the
> information that is used in deciding which overload it should be
> resolved to is encoded in the types and value categories of the
> arguments to that list which are forwardable without problems.
>
OK, *now* we're getting somewhere; I didn't get that you were talking about
a *language* change that keys off of a specific library type.
I actually rather like this. I'm not certain it needs to be that verbose,
since I'd like to see it used more globally. I'd hate to have to do
`vector.emplace_back(std::nolist, ...)` all the time. And I'd also like a
companion `inlist` type that forces the rest of a braced-init-list to be
considered an initialization list. That way, you can express your intent to
not call a constructor.
Personally however, I don't see any difference between these two approaches
in terms of which initialization is more "uniform". Both require specific
language changes to 8.5.4 and 13.3.1.7 in order to make them work. Both
require the user to use special syntax. And so froth. The fact that it's a
parameter type vs a syntactic construct is just an implementation detail.
Yes, this "implementation detail" means that one is more easily forwarded
than the other. But I don't feel that one being directly forwarded and one
not makes it more or less "uniform". You're still changing how the language
interprets the braced-init-list, which is what you argued was non-"uniform"
about my solution.
But ultimately, what I care about is that the ambiguity is fixed, while
still using uniform initialization syntax. And this does that. So I'm
content with this syntax, in general.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_843_22407624.1359651085781
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Thursday, January 31, 2013 4:26:58 AM UTC-8, Sebastian Gesemann =
wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8=
ex;border-left: 1px #ccc solid;padding-left: 1ex;">On Wed, Jan 30, 2013 at =
10:23 PM, Nicol Bolas wrote:
<br>> On Wednesday, January 30, 2013 5:36:21 AM UTC-8, Sebastian Geseman=
n wrote <br></blockquote><blockquote class=3D"gmail_quote" style=3D"margin:=
0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">> =
Furthermore, different library authors will have different ideas about
<br>> different syntax.
<br>> Some will prefer the first argument to disambiguate. Some
<br>> will use the last. They will use different types, thus forcing you=
to use a
<br>> different type name for disambiguation for different libraries. An=
d so
<br>> forth.
<br>
<br>Oh, sorry, I guess I wasn't clear enough and you misunderstood. I was
<br>not talking about a library solution. I was talking about giving the
<br>type of "nolist" special treatment from the compiler in the following
<br>way:
<br>
<br> struct foo {
<br> foo(int); // #1
<br> foo(initializer_list<int>) // #2
<br> };
<br>
<br> int main() {
<br> foo x {nolist,29}; // picks #1
<br> foo y {17}; // picks #2
<br> }
<br>
<br>without a constructor every receiving a "nolist" parameter. The beauty
<br>of it is that we actually don't have to special case this in
<br>forwarding code since nolist is just one of the parameters. This would
<br>be an example of a truly uniform initialization where all the
<br>information that is used in deciding which overload it should be
<br>resolved to is encoded in the types and value categories of the
<br>arguments to that list which are forwardable without problems.<br></blo=
ckquote><div><br>OK, <i>now</i> we're getting somewhere; I didn't get that =
you were talking about a <i>language</i> change that keys off of a specific=
library type.<br><br>I actually rather like this. I'm not certain it needs=
to be that verbose, since I'd like to see it used more globally. I'd hate =
to have to do `vector.emplace_back(std::nolist, ...)` all the time. And I'd=
also like a companion `inlist` type that forces the rest of a braced-init-=
list to be considered an initialization list. That way, you can express you=
r intent to not call a constructor.<br><br>Personally however, I don't see =
any difference between these two approaches in terms of which initializatio=
n is more "uniform". Both require specific language changes to 8.5.4 and 13=
..3.1.7 in order to make them work. Both require the user to use special syn=
tax. And so froth. The fact that it's a parameter type vs a syntactic const=
ruct is just an implementation detail.<br><br>Yes, this "implementation det=
ail" means that one is more easily forwarded than the other. But I don't fe=
el that one being directly forwarded and one not makes it more or less "uni=
form". You're still changing how the language interprets the braced-init-li=
st, which is what you argued was non-"uniform" about my solution.<br><br>Bu=
t ultimately, what I care about is that the ambiguity is fixed, while still=
using uniform initialization syntax. And this does that. So I'm content wi=
th this syntax, in general.<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_843_22407624.1359651085781--
.
Author: vattilah-groups@yahoo.co.uk
Date: Thu, 31 Jan 2013 14:22:23 -0800 (PST)
Raw View
------=_Part_1223_16186057.1359670943167
Content-Type: text/plain; charset=ISO-8859-1
On Thursday, January 31, 2013 12:26:58 PM UTC, Sebastian Gesemann wrote:
> Oh, sorry, I guess I wasn't clear enough and you misunderstood. I was
> not talking about a library solution. I was talking about giving the
> type of "nolist" special treatment from the compiler in the following
> way:
>
> struct foo {
> foo(int); // #1
> foo(initializer_list<int>) // #2
> };
>
> int main() {
> foo x {nolist,29}; // picks #1
> foo y {17}; // picks #2
> }
As a further exploration of the design space, rather than making `nolist`
an instance of a special type with special treatment from the compiler,
could we make `__nolist` a new cv-qualifier with the function std::nolist
to do the conversion (thus getting similarity with std::move and
std::forward). For example,
struct foo {
foo(int); // #1
foo(initializer_list<int>) // #2
};
int main() {
foo x {nolist(29)}; // picks #1
foo y {17}; // picks #2
}
Here `nolist(29)` casts `29` from `int` to `__nolist int`, which is
convertible to `int`, but not `initializer_list <int>`, for overload
resolution.
Regards,
Vidar Hasfjord
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_1223_16186057.1359670943167
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<p>On Thursday, January 31, 2013 12:26:58 PM UTC, Sebastian Gesemann wrote:=
<br>> Oh, sorry, I guess I wasn't clear enough and you misunderstood. I =
was <br>> not talking about a library solution. I was talking about givi=
ng the <br>> type of "nolist" special treatment from the compiler in the=
following <br>> way: <br>> <br>> struct foo { <br>> =
; foo(int); // #1 <br>> foo(initiali=
zer_list<int>) // #2 <br>> }; <br>> <br>> &=
nbsp; int main() { <br>> foo x {nolist,29}; // p=
icks #1 <br>> foo y {17}; // picks #2 <br>>&n=
bsp; } </p><p>As a further exploration of the design space, rather th=
an making `nolist` an instance of a special type with special treatment fro=
m the compiler, could we make `__nolist` a new cv-qualifier with the functi=
on std::nolist to do the conversion (thus getting similarity with std::move=
and std::forward). For example,</p><p> struct foo { <br> =
foo(int); // #1 <br> foo(initializer_list<int>) // =
#2 <br> }; </p><p> int main() { <br> foo x {n=
olist(29)}; // picks #1<br> foo y {17}; // picks #2 <br>&=
nbsp; } </p><p>Here `nolist(29)` casts `29` from `int` to `__nolist int`, w=
hich is convertible to `int`, but not `initializer_list <int>`, for o=
verload resolution.</p><p>Regards,<br>Vidar Hasfjord<br></p>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_1223_16186057.1359670943167--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Thu, 31 Jan 2013 14:44:27 -0800 (PST)
Raw View
------=_Part_215_12673806.1359672267039
Content-Type: text/plain; charset=ISO-8859-1
On Thursday, January 31, 2013 2:22:23 PM UTC-8, vattila...@yahoo.co.uk
wrote:
>
> On Thursday, January 31, 2013 12:26:58 PM UTC, Sebastian Gesemann wrote:
> > Oh, sorry, I guess I wasn't clear enough and you misunderstood. I was
> > not talking about a library solution. I was talking about giving the
> > type of "nolist" special treatment from the compiler in the following
> > way:
> >
> > struct foo {
> > foo(int); // #1
> > foo(initializer_list<int>) // #2
> > };
> >
> > int main() {
> > foo x {nolist,29}; // picks #1
> > foo y {17}; // picks #2
> > }
>
> As a further exploration of the design space, rather than making `nolist`
> an instance of a special type with special treatment from the compiler,
> could we make `__nolist` a new cv-qualifier with the function std::nolist
> to do the conversion (thus getting similarity with std::move and
> std::forward). For example,
>
> struct foo {
> foo(int); // #1
> foo(initializer_list<int>) // #2
> };
>
> int main() {
> foo x {nolist(29)}; // picks #1
> foo y {17}; // picks #2
> }
>
> Here `nolist(29)` casts `29` from `int` to `__nolist int`, which is
> convertible to `int`, but not `initializer_list <int>`, for overload
> resolution.
>
What purpose does this serve besides complicating the feature? We have no
need for this "cv qualifier" in any other place than with braced-init-lists
and parameters to forwarding functions leading to a braced-init-list.
It also makes it look uglier, since `nolist` appears to be modifying the
value. Does that mean that each value in the braced-init-list should have
`nolist` applied to it? If I have `std::vector<int>{30, 40}`, am I supposed
to do `std::vector<int>{nolist(30, 40)}` or `std::vector<int>{nolist(30),
40}` or `std::vector<int>{nolist(30), nolist(40)}`? Which element does the
compiler look to to decide whether to look at initializer-list constructors?
How does it work with copying elements and so forth; does it return an
rvalue-reference, thus potentially provoking an unnecessary (depending on
how it is defined)?
Having it be a parameter with a type makes it work effectively with other
things (ie: forwarding), and it makes the syntax much clearer to the user
in how it is meant to be applied. It doesn't modify a value; it *is* a
value. It also allows you to add new types, like `inlist` which forces the
use of initializer_list constructors and fails if none are found.
I don't see the point of "exploring the design space" if that exploration
doesn't actually uncover something that's better in any way. It's just *
different*.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_215_12673806.1359672267039
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Thursday, January 31, 2013 2:22:23 PM UTC-8, vattila...@yahoo.co=
..uk wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:=
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><p>On Thursday, Janu=
ary 31, 2013 12:26:58 PM UTC, Sebastian Gesemann wrote:<br>> Oh, sorry, =
I guess I wasn't clear enough and you misunderstood. I was <br>> not tal=
king about a library solution. I was talking about giving the <br>> type=
of "nolist" special treatment from the compiler in the following <br>> =
way: <br>> <br>> struct foo { <br>> foo(in=
t); // #1 <br>> foo(initializer_list<int>)=
// #2 <br>> }; <br>> <br>> int main() { <=
br>> foo x {nolist,29}; // picks #1 <br>>&nbs=
p; foo y {17}; // picks #2 <br>> } </p><p>=
As a further exploration of the design space, rather than making `nolist` a=
n instance of a special type with special treatment from the compiler, coul=
d we make `__nolist` a new cv-qualifier with the function std::nolist to do=
the conversion (thus getting similarity with std::move and std::forward). =
For example,</p><p> struct foo { <br> foo(int); // #1 <br>=
foo(initializer_list<int>) // #2 <br> }; </p=
><p> int main() { <br> foo x {nolist(29)}; // picks=
#1<br> foo y {17}; // picks #2 <br> } </p><p>Here =
`nolist(29)` casts `29` from `int` to `__nolist int`, which is convertible =
to `int`, but not `initializer_list <int>`, for overload resolution.<=
/p></blockquote><div><br>What purpose does this serve besides complicating =
the feature? We have no need for this "cv qualifier" in any other place tha=
n with braced-init-lists and parameters to forwarding functions leading to =
a braced-init-list.<br><br>It also makes it look uglier, since `nolist` app=
ears to be modifying the value. Does that mean that each value in the brace=
d-init-list should have `nolist` applied to it? If I have `std::vector<i=
nt>{30, 40}`, am I supposed to do `std::vector<int>{nolist(30, 40)=
}` or `std::vector<int>{nolist(30), 40}` or `std::vector<int>{n=
olist(30), nolist(40)}`? Which element does the compiler look to to decide =
whether to look at initializer-list constructors?<br><br>How does it work w=
ith copying elements and so forth; does it return an rvalue-reference, thus=
potentially provoking an unnecessary (depending on how it is defined)?<br>=
<br>Having it be a parameter with a type makes it work effectively with oth=
er things (ie: forwarding), and it makes the syntax much clearer to the use=
r in how it is meant to be applied. It doesn't modify a value; it <i>is</i>=
a value. It also allows you to add new types, like `inlist` which forces t=
he use of initializer_list constructors and fails if none are found.<br><br=
>I don't see the point of "exploring the design space" if that exploration =
doesn't actually uncover something that's better in any way. It's just <i>d=
ifferent</i>.<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_215_12673806.1359672267039--
.
Author: DeadMG <wolfeinstein@gmail.com>
Date: Fri, 1 Feb 2013 02:24:08 -0800 (PST)
Raw View
------=_Part_739_26344944.1359714248056
Content-Type: text/plain; charset=ISO-8859-1
On Thursday, January 31, 2013 2:19:03 PM UTC, Nikolay Ivchenkov wrote:
> On Thursday, January 31, 2013 3:44:34 PM UTC+4, DeadMG wrote:
>>
>> It has one parameter for each data member which is the type of that data
>> member that is then forwarded to it. So in the case of X, it would be
>>
>> X(std::string __s1 = std::string(), std::string __s2 = std::string(),
>> std::unique_ptr<std::string> __s3 = std::unique_ptr<std::string>())
>> : s1(std::forward<std::string>(__s1)),
>> s2(std::forward<std::string>(__s2)),
>> p(std::forward<std::unique_ptr<std::string>>(__s3)) {}
>>
>> Considering, however, immovable types, perhaps it would be more accurate
>> (although less convenient) to specify as
>>
>> X(std::string __s1)
>> : s1(std::forward<std::string>(s1)), s2(), p() {}
>> X(std::string __s1, std::string __s2)
>> : s1(std::forward<std::string(__s1)),
>> s2(std::forward<std::string>(__s2)), p() {}
>>
>> This should retain the correct semantics in terms of immovable types, and
>> types which behave differently when value-initialized, such as int.
>>
>
> Is that more simple than just defining initialization
>
> AggregateType x(items...);
>
> to be equivalent to
>
> AggregateType x{items...};
>
> ? (Note that I don't suggest to change the rules so)
>
> And how about efficiency? Your two-step initialization of members is
> potentially less efficient than one-step initialization that takes place in
> an aggregate initialization.
>
The constructor is a magic compiler function. It can be magically
efficient. In addition, defining () in terms of {} would make for a simpler
change, but wouldn't reduce the Standard complexity, I think, whereas
removing aggregate initialization in general would.
> Finally, AggregateType(x) and AggregateType{x} may have different meaning
> - see example below:
>
> #include <cstddef>
> #include <iostream>
> #include <string>
> #include <utility>
>
> #define FORWARD(x) static_cast<decltype(x) &&>(x)
>
> template <class T1, class T2>
> struct P
> {
> template <class U1, class U2>
> P(U1 &&u1, U2 &&u2) :
> p(FORWARD(u1), FORWARD(u2)) {}
>
> template <class T>
> operator T() const
> { return {p.first, p.second}; }
>
> std::pair<T1, T2> p;
> };
>
> struct A
> {
> std::string s;
> std::size_t n;
> };
>
> int main()
> {
> P<std::string, std::size_t> p("whole", 1u);
> A a1(p);
> A a2{p};
> std::cout << a1.s << " " << a1.n << std::endl;
> std::cout << a2.s << " " << a2.n << std::endl;
> }
>
> http://liveworkspace.org/code/1MU15f$0
>
Well, that's a nasty surprise. I hadn't considered a data type that could
convert to both an aggregate structure as a whole, and a single member
within it. Under the proposed change, this would be ambiguous.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_739_26344944.1359714248056
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Thursday, January 31, 2013 2:19:03 PM UTC, Nikolay Ivchenkov wrote:<br><=
blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bord=
er-left: 1px #ccc solid;padding-left: 1ex;">On Thursday, January 31, 2013 3=
:44:34 PM UTC+4, DeadMG wrote:<blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex">It ha=
s one parameter for each data member which is the type of that data member =
that is then forwarded to it. So in the case of X, it would be<div><br></di=
v><div> X(std::string __s1 =3D std::string(), std::string __s2=
=3D std::string(), std::unique_ptr<std::string> __s3 =3D std::unique=
_ptr<std::string>()<wbr>)</div><div> : s1(=
std::forward<std::string>(_<wbr>_s1)), s2(std::forward<std::string=
>(_<wbr>_s2)), p(std::forward<std::unique_<wbr>ptr<std::string>=
>(__s3)) {}</div><div><br></div><div>Considering, however, immovable typ=
es, perhaps it would be more accurate (although less convenient) to specify=
as</div><div><br></div><div> X(std::string __s1)</div><div>&n=
bsp; : s1(std::forward<std::string>(<wbr>s1)), s=
2(), p() {}</div><div> X(std::string __s1, std::string __s2)</=
div><div> : s1(std::forward<std::string(__<wb=
r>s1)), s2(std::forward<std::string>(_<wbr>_s2)), p() {}</div><div><b=
r></div><div>This should retain the correct semantics in terms of immovable=
types, and types which behave differently when value-initialized, such as =
int.</div></blockquote><div><br>Is that more simple than just defining init=
ialization<br><br> AggregateType x(items...);<br><br>to b=
e equivalent to<br><br> AggregateType x{items...};<br><br=
>? (Note that I don't suggest to change the rules so)<br><br>And how about =
efficiency? Your two-step initialization of members is potentially less eff=
icient than one-step initialization that takes place in an aggregate initia=
lization.<br></div></blockquote><div><br></div><div>The constructor is a ma=
gic compiler function. It can be magically efficient. In addition, defining=
() in terms of {} would make for a simpler change, but wouldn't reduce the=
Standard complexity, I think, whereas removing aggregate initialization in=
general would.</div><div> </div><blockquote class=3D"gmail_quote" sty=
le=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left=
: 1ex;"><div>Finally, AggregateType(x) and AggregateType{x} may have differ=
ent meaning - see example below:<br><br> #include <cst=
ddef><br> #include <iostream><br> &nb=
sp; #include <string><br> #include <utility><=
br><br> #define FORWARD(x) static_cast<decltype(x) &am=
p;&>(x)<br><br> template <class T1, class T2>=
;<br> struct P<br> &nb=
sp; {<br> template <class U1, =
class U2><br>  =
; P(U1 &&u1, U2 &&u2) :<br> &n=
bsp; p(FORWARD(=
u1), FORWARD(u2)) {}<br><br> temp=
late <class T><br> &nb=
sp; operator T() const<br> &=
nbsp; { return {p.first, p.=
second}; }<br><br> std::pair<T=
1, T2> p;<br> };<br><br> struct A<br=
> {<br> std::st=
ring s;<br> std::size_t n;<br>&nb=
sp; };<br><br> int main()<br> &nbs=
p; {<br> P<std::string, std::s=
ize_t> p("whole", 1u);<br> A a=
1(p);<br> A a2{p};<br>  =
; std::cout << a1.s << " " <&l=
t; a1.n << std::endl;<br> s=
td::cout << a2.s << " " << a2.n << std::endl;<br>&n=
bsp; }<br><br><a href=3D"http://liveworkspace.org/code/1MU15f$0=
" target=3D"_blank">http://liveworkspace.org/code/<wbr>1MU15f$0</a></div></=
blockquote><div><br></div><div>Well, that's a nasty surprise. I hadn't cons=
idered a data type that could convert to both an aggregate structure as a w=
hole, and a single member within it. Under the proposed change, this would =
be ambiguous.</div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_739_26344944.1359714248056--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Fri, 1 Feb 2013 05:58:14 -0800 (PST)
Raw View
------=_Part_374_956283.1359727094934
Content-Type: text/plain; charset=ISO-8859-1
On Thursday, January 31, 2013 6:41:20 PM UTC+4, Sebastian Gesemann wrote:
>
>
> How would you implement an allocator's construct function template?
>
> new(ptr) T(forward<Args>(args)...); // #1
> new(ptr) T{forward<Args>(args)...}; // #2
>
> With #1 you can't initialize aggregates and picking the
> initializer_list constructor of a vector<int> requires you to
> explicitly pass a std::initializer_list object. With #2 and
> T=vector<int> you can't initialize the vector to a certain size.
If we want to resolve library issue 2089
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3516.html#2089),
the changes in the specification should not affect existing code.
struct X
{
explicit X(unsigned char);
/*...*/
};
void f()
{
std::vector<X> v;
v.emplace_back(4);
}
Changing () to {c:} in std::allocator's construct() is a non-viable
solution, because {c:} renders narrowing conversions ill-formed. Obviously,
value 4 can be stored in an object of type unsigned char, but when it is
forwarded by emplace_back, it becomes a non-constant expression of type int
and the further conversion of non-constexpr int to unsigned char will be
considered as narrowing. In addition,
AggregateType a{c: x};
and
AggregateType a(x);
may be well-formed initializations with different semantics (as shown
above), so breaking change could be silent.
Changing () to {nolist, ...} in std::allocator's construct() is a
non-viable solution for the same reasons + we would have problems with a
code like this:
std::vector<std::vector<int>> v;
v.emplace_back(3, 4);
// was: 3 items with value 4
// became: 2 items with values 3 and 4
If we define T(std::itemwise, ...) as an itemwise initialization (aggregate
initialization or initialization with an initializer-list constructor),
this could solve the issue without affecting any existing code (where
'itemwise' is not defined as a macro name), but we would have irregular
forwarding then:
template <class T>
class Wrapper
{
public:
template <class... Params>
Wrapper(Params &&... params) : m_t(FORWARD(params)...) {}
/*...*/
private:
T m_t;
};
auto p = make_shared<Wrapper<std::vector<int>>>(std::itemwise, 11, 22);
Here std::itemwise cannot be forwarded by the Wrapper's constructor. We
could introduce an additional parameter and force users to specify two tags:
constexpr struct initialize_t {} initialize;
template <class T>
class Wrapper
{
public:
template <class... Params>
Wrapper(initialize_t, Params &&... params) :
m_t(FORWARD(params)...) {}
/*...*/
private:
T m_t;
};
auto p = make_shared<Wrapper<std::vector<int>>>(initialize,
std::itemwise, 11, 22);
but I would say that such a code looks too verbose.
Forwardable heterogeneous initializer lists for itemwise initialization
seem to be the best solution:
1) there would be no need to change library specification: existing ()
syntax would work fine;
2) any well-defined existing code would remain well-defined and have the
same semantics as before;
3) itemwise and non-itemwise initialization could be expressed
unambiguously (for both aggregates and non-aggregates):
struct X
{
template <class T>
operator T();
};
struct A
{
std::string s;
};
void f(X &x)
{
auto p1 = std::make_shared<A>(x);
// non-itemwise initialization
// T = A
auto p2 = std::make_shared<A>(+{x});
// itemwise initialization
// T = std::string
auto p3 = std::make_shared<std::vector<int>>(5, 1);
// non-itemwise initialization
// creates 5 elements with value 1
auto p4 = std::make_shared<std::vector<int>>(+{5, 1});
// itemwise initialization
// creates 2 elements with values 5 and 1
}
4) nested initializer lists could be handled like plain values;
5) notation +{} is fairly short;
6) library issue 2051
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3516.html#2051)
could also be resolved in simple and natural manner.
I'd like to mention that IIRC a commitee member hinted at removing the
> irregularity between auto and function template argument deduction.
IIRC, such irregularity was introduced intentionally, because templates may
be overloaded and deducing a braced-init-list as a specialization of
std::initializer_list could lead to surprising results.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_374_956283.1359727094934
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Thursday, January 31, 2013 6:41:20 PM UTC+4, Sebastian Gesemann wrote:<b=
lockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;borde=
r-left: 1px #ccc solid;padding-left: 1ex;"><br>How would you implement an a=
llocator's construct function template?
<br>
<br> new(ptr) T(forward<Args>(args)...); // #1
<br> new(ptr) T{forward<Args>(args)...}; // #2
<br>
<br>With #1 you can't initialize aggregates and picking the
<br>initializer_list constructor of a vector<int> requires you to
<br>explicitly pass a std::initializer_list object. With #2 and
<br>T=3Dvector<int> you can't initialize the vector to a certain size=
..</blockquote><div><br>If we want to resolve library issue 2089 (http://www=
..open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3516.html#2089), the changes=
in the specification should not affect existing code.<br><br> &=
nbsp; struct X<br> {<br> &nb=
sp; explicit X(unsigned char);<br>  =
; /*...*/<br> };<br><br> void f()=
<br> {<br> std:=
:vector<X> v;<br> v.emplace=
_back(4);<br> }<br><br>Changing () to {c:} in std::alloca=
tor's construct() is a non-viable solution, because {c:} renders narrowing =
conversions ill-formed. Obviously, value 4 can be stored in an object of ty=
pe unsigned char, but when it is forwarded by emplace_back, it becomes a no=
n-constant expression of type int and the further conversion of non-constex=
pr int to unsigned char will be considered as narrowing. In addition,<br><b=
r> AggregateType a{c: x};<br><br>and<br><br> &=
nbsp; AggregateType a(x);<br><br>may be well-formed initializations with di=
fferent semantics (as shown above), so breaking change could be silent.<br>=
<br>Changing () to {nolist, ...} in std::allocator's construct() is a non-v=
iable solution for the same reasons + we would have problems with a code li=
ke this:<br><br> std::vector<std::vector<int>>=
; v;<br> v.emplace_back(3, 4);<br> // w=
as: 3 items with value 4<br> // became: 2 items with valu=
es 3 and 4<br><br>If we define T(std::itemwise, ...) as an itemwise initial=
ization (aggregate initialization or initialization with an initializer-lis=
t constructor), this could solve the issue without affecting any existing c=
ode (where 'itemwise' is not defined as a macro name), but we would have ir=
regular forwarding then:<br><br> template <class T>=
<br> class Wrapper<br>  =
; {<br> public:<br> &n=
bsp; template <class... Params><br> &nbs=
p; Wrapper(Params &&... params)=
: m_t(FORWARD(params)...) {}<br> =
/*...*/<br> private:<br> &n=
bsp; T m_t;<br> };<br> <br> =
auto p =3D make_shared<Wrapper<std::vector<int>>=
;>(std::itemwise, 11, 22);<br><br>Here std::itemwise cannot be forwarded=
by the Wrapper's constructor. We could introduce an additional parameter a=
nd force users to specify two tags:<br><br> constexpr str=
uct initialize_t {} initialize;<br><br> template <clas=
s T><br> class Wrapper<br>&nbs=
p; {<br> public:<br> &=
nbsp; template <class... Params><br> &nb=
sp; Wrapper(initialize_t, Params =
&&... params) : m_t(FORWARD(params)...) {}<br> &nb=
sp; /*...*/<br> private:<br>  =
; T m_t;<br> };<br><br>&nbs=
p; auto p =3D make_shared<Wrapper<std::vector<int>&=
gt;>(initialize, std::itemwise, 11, 22);<br><br>but I would say that suc=
h a code looks too verbose.<br><br>Forwardable heterogeneous initializer li=
sts for itemwise initialization seem to be the best solution:<br>1) there w=
ould be no need to change library specification: existing () syntax would w=
ork fine;<br>2) any well-defined existing code would remain well-defined an=
d have the same semantics as before;<br>3) itemwise and non-itemwise initia=
lization could be expressed unambiguously (for both aggregates and non-aggr=
egates):<br><br> struct X<br> {<br>&nbs=
p; template <class T><br> &n=
bsp; operator T();<br=
> };<br> <br> struct =
A<br> {<br> std=
::string s;<br> };<br> <br> =
void f(X &x)<br> {<br> =
auto p1 =3D std::make_shared<A>(x);<br>  =
; // non-itemwise initialization<br> &nb=
sp; // T =3D A<br><br>  =
; auto p2 =3D std::make_shared<A>(+{x});<br> &=
nbsp; // itemwise initialization<br> &nb=
sp; // T =3D std::string<br><br> &=
nbsp; auto p3 =3D std::make_shared<std::vector&l=
t;int>>(5, 1);<br> // non-i=
temwise initialization<br> // cre=
ates 5 elements with value 1<br><br> &nb=
sp; auto p4 =3D std::make_shared<std::vector<int>>(+{5, 1});<br=
> // itemwise initialization<br>&=
nbsp; // creates 2 elements with values=
5 and 1<br> }<br><br>4) nested initializer lists could b=
e handled like plain values;<br>5) notation +{} is fairly short;<br>6) libr=
ary issue 2051 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n35=
16.html#2051) could also be resolved in simple and natural manner.<br><br><=
/div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;">
I'd like to mention that IIRC a commitee member hinted at removing the
<br>irregularity between auto and function template argument deduction.</bl=
ockquote><div><br>IIRC, such irregularity was introduced intentionally, bec=
ause templates may be overloaded and deducing a braced-init-list as a speci=
alization of std::initializer_list could lead to surprising results.</div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_374_956283.1359727094934--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Fri, 1 Feb 2013 06:10:41 -0800 (PST)
Raw View
------=_Part_1864_32063703.1359727841056
Content-Type: text/plain; charset=ISO-8859-1
On Friday, February 1, 2013 2:24:08 PM UTC+4, DeadMG wrote:
>
>
> The constructor is a magic compiler function. It can be magically
> efficient.
>
Copy/move elision is not allowed on xvalues produced by std::forward (only
general "as-if" rule can be applied). If you need special rules for
aggregate ctors, your idea doesn't look simple.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_1864_32063703.1359727841056
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Friday, February 1, 2013 2:24:08 PM UTC+4, DeadMG wrote:<blockquote clas=
s=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #c=
cc solid;padding-left: 1ex;"><br><div>The constructor is a magic compiler f=
unction. It can be magically efficient.</div></blockquote><div><br>Copy/mov=
e elision is not allowed on xvalues produced by std::forward (only general =
"as-if" rule can be applied). If you need special rules for aggregate ctors=
, your idea doesn't look simple.</div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_1864_32063703.1359727841056--
.
Author: malteskarupke@gmail.com
Date: Sat, 2 Feb 2013 20:15:16 -0800 (PST)
Raw View
------=_Part_803_6709885.1359864916926
Content-Type: text/plain; charset=ISO-8859-1
On Tuesday, January 29, 2013 7:55:09 AM UTC-5, Nicol Bolas wrote:
>
> On Tuesday, January 29, 2013 4:04:42 AM UTC-8, Malte Skarupke wrote:
>>
>> The construct_uniform was just an example to illustrate the effects of my
>> proposed change. It is not part of the proposal.
>>
>> The proposal is to drop the list initialization preference for template
>> types and partially specialized templates. Non-template types and fully
>> specialized templates keep the current behavior.
>>
>> Now read that email again for examples.
>> You will find that that change solves all the problems mentioned in this
>> thread without requiring new syntax.
>>
> Here's one it doesn't solve:
>
> void SomeFunc(std::vector<int> v);
>
> SomeFunc({10});
>
> There's no type deduction happening here.
>
> Yes, it would mean that you have to fall back to () initialization
>> sometimes,
>>
> If you have to abandon uniform initialization syntax, it's not solving the
> problem. It's *hiding* the problem. The proposal is called "Towards *more*uniform initialization", not less.
>
>
>> (as you do now) but it is superior to the current uniform initialization
>> rules in that it doesn't give you unexpected behavior.
>>
> But it *does* give unexpected behavior. It gives the same unexpected
> behavior as it currently does in non-template deduction contexts. That's
> how you defined it. So something as simple as this:
>
> std::vector<int> v{20};
>
> Does not get fixed. You still cannot access std::vector<int>'s sizing
> constructor with uniform initialization syntax.
>
> You're basically saying that it's safe(er) to use {} in templates, but not
> in non-template code.
>
> You're too focused on just the template issue. The fundamental issue is
> the fact that the user has no ability to decide which constructors should
> be preferable. Coming up with ad-hoc rules as you did is no solution; we
> tried that with the current {} syntax, and it turns out that it didn't
> work. We have to accept that the user needs a way to *explicitly* state
> whether a particular braced-init-list should be used as an initializer list
> constructor parameter or as arguments to a constructor.
>
> Also, it should be noted that this is probably the first feature that has
> been suggested where behavior of code changes based on the fact that a
> named type just so happened to have come from a template rather than being
> hard-coded. I don't like that idea; template code is not a special land
> where the rules of C++ apply differently. It should work the same as
> anywhere else.
>
> Oh, and one more thing: it's a breaking change. Granted, it would only
> break code that's somewhat dangerous anyway, but it's still a breaking
> change. Mine isn't.
>
Yes, I am not very interested in creating a new syntax that could be used
to call all constructors. I don't think that it's a problem that you have
to use () syntax sometimes.
I am more interested in fixing the current syntax. If you were to introduce
a new syntax, what you would essentially be doing is deprecating the
current one because there would be very few reasons to ever use it again.
If that means that I am off topic in this thread then I can start a new one
about fixing the current syntax.
But you were right in that I was too focused on the template problem.
Because the same problems exist for non-template code. Consider this:
struct Widget
{
Widget(int);
operator int() const;
};
int main()
{
Widget a{5};
Widget b{a};
}
If I now add the following constructor, I would break both of those lines:
struct S{ S(int) {} };
Widget(std::initializer_list<S>);
And this change in behavior would be silent. Meaning initializer_list
constructors have the potential to become a mess in code maintenance. You
have to be really careful about introducing an initializer_list constructor
to a class that is already initialized using uniform initialization. And
you have to be really careful about introducing conversion operators to
classes that are used as arguments in uniform initialization.
Basically you need to look into your crystal ball of choice and only use
uniform initialization if you know that a class will never get an
initializer_list constructor.
Because of that I think we need two changes to the uniform initialization
rules:
1. The change I mentioned before about dropping initializer_list preference
in template code
2. For non-template code and fully specialized templates, an
initializer_list constructor should only be preferred if no conversion is
required.
I think that these changes are necessary even if a new syntax is adopted,
because otherwise the old syntax would never be used. And I think that
these changes would not break a significant amount of existing code. The
code that would be broken by this was probably either not doing what you
were expecting it to do anyway, or it should have been at least ambiguous
to begin with, or the compiler will give you an error.
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_803_6709885.1359864916926
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br>On Tuesday, January 29, 2013 7:55:09 AM UTC-5, Nicol Bolas wrote:<block=
quote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-le=
ft: 1px #ccc solid;padding-left: 1ex;">On Tuesday, January 29, 2013 4:04:42=
AM UTC-8, Malte Skarupke wrote:<blockquote class=3D"gmail_quote" style=3D"=
margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><p>=
The construct_uniform was just an example to illustrate the effects of my p=
roposed change. It is not part of the proposal.</p>
<p>The proposal is to drop the list initialization preference for template =
types and partially specialized templates. Non-template types and fully spe=
cialized templates keep the current behavior.</p>
<p>Now read that email again for examples.<br>
You will find that that change solves all the problems mentioned in this th=
read without requiring new syntax.</p></blockquote><div>Here's one it doesn=
't solve:<br><br><div style=3D"background-color:rgb(250,250,250);border-col=
or:rgb(187,187,187);border-style:solid;border-width:1px;word-wrap:break-wor=
d"><code><div><span style=3D"color:#008">void</span><span style=3D"color:#0=
00"> </span><span style=3D"color:#606">SomeFunc</span><span style=3D"color:=
#660">(</span><span style=3D"color:#000">std</span><span style=3D"color:#66=
0">::</span><span style=3D"color:#000">vector</span><span style=3D"color:#0=
80"><int></span><span style=3D"color:#000"> v</span><span style=3D"co=
lor:#660">);</span><span style=3D"color:#000"><br><br></span><span style=3D=
"color:#606">SomeFunc</span><span style=3D"color:#660">({</span><span style=
=3D"color:#066">10</span><span style=3D"color:#660">});</span></div></code>=
</div><br>There's no type deduction happening here.<br><br></div><blockquot=
e class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px=
#ccc solid;padding-left:1ex">
<p>Yes, it would mean that you have to fall back to () initialization somet=
imes,</p></blockquote><div>If you have to abandon uniform initialization sy=
ntax, it's not solving the problem. It's <i>hiding</i> the problem. The pro=
posal is called "Towards <i>more</i> uniform initialization", not less.<br>=
</div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left=
:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><p> (as you do now) but=
it is superior to the current uniform initialization rules in that it does=
n't give you unexpected behavior.</p></blockquote><div>But it <i>does</i> g=
ive unexpected behavior. It gives the same unexpected behavior as it curren=
tly does in non-template deduction contexts. That's how you defined it. So =
something as simple as this:<br><br><div style=3D"background-color:rgb(250,=
250,250);border-color:rgb(187,187,187);border-style:solid;border-width:1px;=
word-wrap:break-word"><code><div><span style=3D"color:#000">std</span><span=
style=3D"color:#660">::</span><span style=3D"color:#000">vector</span><spa=
n style=3D"color:#080"><int></span><span style=3D"color:#000"> v</spa=
n><span style=3D"color:#660">{</span><span style=3D"color:#066">20</span><s=
pan style=3D"color:#660">};</span></div></code></div><br>Does not get fixed=
.. You still cannot access std::vector<int>'s sizing constructor with =
uniform initialization syntax.<br><br>You're basically saying that it's saf=
e(er) to use {} in templates, but not in non-template code.<br><br>You're t=
oo focused on just the template issue. The fundamental issue is the fact th=
at the user has no ability to decide which constructors should be preferabl=
e. Coming up with ad-hoc rules as you did is no solution; we tried that wit=
h the current {} syntax, and it turns out that it didn't work. We have to a=
ccept that the user needs a way to <i>explicitly</i> state whether a partic=
ular braced-init-list should be used as an initializer list constructor par=
ameter or as arguments to a constructor.<br><br>Also, it should be noted th=
at this is probably the first feature that has been suggested where behavio=
r of code changes based on the fact that a named type just so happened to h=
ave come from a template rather than being hard-coded. I don't like that id=
ea; template code is not a special land where the rules of C++ apply differ=
ently. It should work the same as anywhere else.<br><br>Oh, and one more th=
ing: it's a breaking change. Granted, it would only break code that's somew=
hat dangerous anyway, but it's still a breaking change. Mine isn't.<br></di=
v></blockquote><div> </div><div><br>Yes, I am not very interested in c=
reating a new syntax that could be=20
used to call all constructors. I don't think that it's a problem that=20
you have to use () syntax sometimes.<br>I am more interested in fixing=20
the current syntax. If you were to introduce a new syntax, what you=20
would essentially be doing is deprecating the current one because there=20
would be very few reasons to ever use it again. If that means that I am=20
off topic in this thread then I can start a new one about fixing the=20
current syntax.<br><br>But you were right in that I was too focused on=20
the template problem. Because the same problems exist for non-template=20
code. Consider this:<br><br><div class=3D"prettyprint" style=3D"background-=
color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: =
solid; border-width: 1px; word-wrap: break-word;"><code class=3D"prettyprin=
t"><div class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styl=
ed-by-prettify">struct</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-prettif=
y">Widget</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><=
br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>  =
; </span><span style=3D"color: #606;" class=3D"styled-by-prettify">Widget</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><spa=
n style=3D"color: #008;" class=3D"styled-by-prettify">int</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"><br> </span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">operator</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #008;" class=3D"styled-by-prettify">int</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">()</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">const</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">};</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br></spa=
n><span style=3D"color: #008;" class=3D"styled-by-prettify">int</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"> main</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">()</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br> </span><span style=3D"color: #60=
6;" class=3D"styled-by-prettify">Widget</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> a</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">{</span><span style=3D"color: #066;" class=3D"styled-b=
y-prettify">5</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">};</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&=
nbsp; </span><span style=3D"color: #606;" class=3D"styled-by-prettif=
y">Widget</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
b</span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify">a</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">};</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">}</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br></span></div></code></div><br><br>If I now add=
the following constructor, I would break both of those lines:<br><br><div =
class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border=
-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wr=
ap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint">=
<span style=3D"color: #008;" class=3D"styled-by-prettify">struct</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> S</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> S</span><span style=3D"color: #660;"=
class=3D"styled-by-prettify">(</span><span style=3D"color: #008;" class=3D=
"styled-by-prettify">int</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">)</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">{}</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">};</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"co=
lor: #606;" class=3D"styled-by-prettify">Widget</span><span style=3D"color:=
#660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify">std</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify">initializer_list</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify"><</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify">S</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">>);</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
<br></span></div></code></div><br>And
this change in behavior would be silent. Meaning initializer_list=20
constructors have the potential to become a mess in code maintenance.=20
You have to be really careful about introducing an initializer_list=20
constructor to a class that is already initialized using uniform=20
initialization. And you have to be really careful about introducing=20
conversion operators to classes that are used as arguments in uniform=20
initialization.<br><br>Basically you need to look into your crystal ball
of choice and only use uniform initialization if you know that a class=20
will never get an initializer_list constructor.<br><br>Because of that I th=
ink we need two changes to the uniform initialization rules:<br>1. The chan=
ge I mentioned before about dropping initializer_list preference in templat=
e code<br>2.
For non-template code and fully specialized templates, an=20
initializer_list constructor should only be preferred if no conversion=20
is required.<br><br>I think that these changes are necessary even if a=20
new syntax is adopted, because otherwise the old syntax would never be=20
used. And I think that these changes would not break a significant=20
amount of existing code. The code that would be broken by this was=20
probably either not doing what you were expecting it to do anyway, or it
should have been at least ambiguous to begin with, or the compiler will gi=
ve you
an error.<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_803_6709885.1359864916926--
.
Author: vattilah-groups@yahoo.co.uk
Date: Sat, 2 Feb 2013 22:31:42 -0800 (PST)
Raw View
------=_Part_801_27744482.1359873102745
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Sunday, 3 February 2013 04:15:16 UTC, maltes...@gmail.com wrote:
>
> [About the silent bugs caused by introducing an il-constructor to a class=
]=20
> Meaning initializer_list constructors have the potential to become a mess=
=20
> in code maintenance. You have to be really careful about introducing an=
=20
> initializer_list constructor to a class that is already initialized using=
=20
> uniform initialization. And you have to be really careful about introduci=
ng=20
> conversion operators to classes that are used as arguments in uniform=20
> initialization.
>
> Basically you need to look into your crystal ball of choice and only use=
=20
> uniform initialization if you know that a class will never get an=20
> initializer_list constructor.
>
> Because of that I think we need two changes to the uniform initialization=
=20
> rules [...]
>
=20
Well put. I think the current il-preference rule has to be looked at, if=20
anything is to be done about this issue.
=20
Lately, I've discovered that brace-initialization does not live up to the=
=20
promise, as concerns prohibiting narrowing conversions =97 at least not in=
=20
the current C++11 implementations. Consider:
=20
struct S {
S(double, int);
S(initializer_list<int>);
};
S s1 {1.2, 1}; // Calls il-constructor (GCC and Clang warn).
initializer_list<int> il {1.2, 1}; // GCC and Clang warn; only MCC refuses.
S s2 {il};
=20
GCC 4.7.2 and Clang 3.2 compile this without error (with -std=3Dc++11 -Wall=
=20
-W -pedantic -O2). Microsoft C/C++ Optimizing Compiler Version 17.00.51025=
=20
(VS2012CTP) refuses the initialization of `il`, but does not warn about=20
narrowing in the initialization of `s1`, even at warning level 4 (/W4).
=20
Without being able to trust brace-initialization not to do narrowing=20
conversions, the argument for always preferring it (which is the central=20
aim of the OP's proposal) is weakened.
=20
As you allude to, and as illustrated in the proposal's motivation, the=20
central aim should be code safety, and in that regard, the potential for=20
the *existing* rules to introduce silent change of behaviour and bugs is=20
the main issue.
=20
Aside: This is very similar to the issue with the rule that a lambda=20
with [=3D] capture list will capture member variables by reference (via=20
this), thus causing wide-spread bugs in programs. Herb Sutter has proposed=
=20
that this rule should be changed to capture members by value, because the *
existing* rule obviously does the wrong thing as regards programmer=20
assumptions. See "Lambda Correctness and Usability Issues" [N3424].
=20
PS. The name "uniform initialization" should preferably be dropped in=20
favour of "brace-initialization". Initialization in C++ is nothing like=20
uniform, even with braces. And since the OP's proposal doesn't make=20
anything more uniform (it just adds more syntax and special rules), it=20
should preferably be renamed to "Towards more brace-initialization".
=20
Regards,
Vidar Hasfjord
=20
--=20
---=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/?hl=3Den.
------=_Part_801_27744482.1359873102745
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Sunday, 3 February 2013 04:15:16 UTC, maltes...@gmail.com wrote:<blockq=
uote style=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-col=
or: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid;" =
class=3D"gmail_quote"><div>[About the silent bugs caused by intro=
ducing an il-constructor to a class] Meaning initializer_list=20
constructors have the potential to become a mess in code maintenance.=20
You have to be really careful about introducing an initializer_list=20
constructor to a class that is already initialized using uniform=20
initialization. And you have to be really careful about introducing=20
conversion operators to classes that are used as arguments in uniform=20
initialization.<br><br>Basically you need to look into your crystal ball
of choice and only use uniform initialization if you know that a class=20
will never get an initializer_list constructor.<br><br>Because of that I th=
ink we need two changes to the uniform initialization rules [...]</div></bl=
ockquote><div> </div><div>Well put. I think the current il-preference =
rule has to be looked at, if anything is to be done about this issue.<=
/div><div> </div><div>Lately, I've discovered that brace-initializatio=
n does not live up to the promise, as concerns prohibiting narrow=
ing conversions =97 at least not in the current C++11 implementations.=
Consider:</div><div> </div><div>struct S {<br> S(double, =
int);<br> S(initializer_list<int>);<br>};</div><div>S s1 =
{1.2, 1}; // Calls il-constructor (GCC and Clang warn).<br>initializer_list=
<int> il {1.2, 1}; // GCC and Clang warn; only MCC refuses.<br>S s2 {=
il};</div><div> </div><div><div>GCC 4.7.2 and Clang 3.2 compile t=
his without error (with -std=3Dc++11 -Wall -W -pedantic -O2). Microsof=
t C/C++ Optimizing Compiler Version 17.00.51025 (VS2012CTP) refuses th=
e initialization of `il`, but does not warn about narrowing in the ini=
tialization of `s1`, even at warning level 4 (/W4).</div><div> </=
div></div><div>Without being able to trust brace-initialization not to do n=
arrowing conversions, the argument for always preferring it (which is =
the central aim of the OP's proposal) is weakened.</div><div> </div><d=
iv>As you allude to, and as illustrated in the proposal's motivat=
ion, the central aim should be code safety, and in that regard, t=
he potential for the <em>existing</em> rules to introduce silent change of =
behaviour and bugs is the main issue.</div><div> </div><div>Aside: Thi=
s is very similar to the issue with the rule that a lambda with [=
=3D] capture list will capture member variables by reference (via this=
), thus causing wide-spread bugs in programs. Herb Sutter has proposed=
that this rule should be changed to capture members by valu=
e, because the <em>existing</em> rule obviously does the wrong thing as reg=
ards programmer assumptions. See "Lambda Correctness and Usability Issues" =
[N3424].</div><div> </div><div>PS. The name "uniform initialization" s=
hould preferably be dropped in favour of "brace-initialization". Initializa=
tion in C++ is nothing like uniform, even with braces. And since the OP's p=
roposal doesn't make anything more uniform (it just adds more syntax and sp=
ecial rules), it should preferably be renamed to "Towards more brace-i=
nitialization".</div><div> </div><div>Regards,</div><div>Vidar Hasfjor=
d</div><div> </div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_801_27744482.1359873102745--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sat, 2 Feb 2013 23:29:22 -0800 (PST)
Raw View
------=_Part_695_11161656.1359876562216
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Saturday, February 2, 2013 10:31:42 PM UTC-8, vattila...@yahoo.co.uk=20
wrote:
>
> On Sunday, 3 February 2013 04:15:16 UTC, maltes...@gmail.com wrote:
>>
>> [About the silent bugs caused by introducing an il-constructor to a=20
>> class] Meaning initializer_list constructors have the potential to becom=
e a=20
>> mess in code maintenance. You have to be really careful about introducin=
g=20
>> an initializer_list constructor to a class that is already initialized=
=20
>> using uniform initialization. And you have to be really careful about=20
>> introducing conversion operators to classes that are used as arguments i=
n=20
>> uniform initialization.
>>
>> Basically you need to look into your crystal ball of choice and only use=
=20
>> uniform initialization if you know that a class will never get an=20
>> initializer_list constructor.
>>
>> Because of that I think we need two changes to the uniform initializatio=
n=20
>> rules [...]
>>
> =20
> Well put. I think the current il-preference rule has to be looked at, if=
=20
> anything is to be done about this issue.
> =20
> Lately, I've discovered that brace-initialization does not live up to the=
=20
> promise, as concerns prohibiting narrowing conversions =97 at least not i=
n=20
> the current C++11 implementations. Consider:
> =20
> struct S {
> S(double, int);
> S(initializer_list<int>);
> };
> S s1 {1.2, 1}; // Calls il-constructor (GCC and Clang warn).
> initializer_list<int> il {1.2, 1}; // GCC and Clang warn; only MCC refuse=
s.
> S s2 {il};
> =20
> GCC 4.7.2 and Clang 3.2 compile this without error (with -std=3Dc++11 -Wa=
ll=20
> -W -pedantic -O2). Microsoft C/C++ Optimizing Compiler Version 17.00.5102=
5=20
> (VS2012CTP) refuses the initialization of `il`, but does not warn about=
=20
> narrowing in the initialization of `s1`, even at warning level 4 (/W4).=
=20
>
=20
> Without being able to trust brace-initialization not to do narrowing=20
> conversions, the argument for always preferring it (which is the central=
=20
> aim of the OP's proposal) is weakened.
>
That's an implementation issue, not a language issue. If implementers are=
=20
getting some of the details wrong, then those are *compiler bugs*. It's=20
like saying that if a compiler's variadic template implementation is=20
screwing up template parameter packs, the language are somehow to blame.
The language feature is clear on this: `S s1{1.2, 1};` cannot work with the=
=20
initializer_list<int> constructor. *Period*. If compilers are allowing it,=
=20
then those *compilers* need to be fixed, not the language.
--=20
---=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/?hl=3Den.
------=_Part_695_11161656.1359876562216
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
<br><br>On Saturday, February 2, 2013 10:31:42 PM UTC-8, vattila...@yahoo.c=
o.uk wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left=
: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On Sunday, 3 Februa=
ry 2013 04:15:16 UTC, <a>maltes...@gmail.com</a> wrote:<blockquote style=
=3D"margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204=
,204);border-left-width:1px;border-left-style:solid" class=3D"gmail_quote">=
<div>[About the silent bugs caused by introducing an il-construct=
or to a class] Meaning initializer_list=20
constructors have the potential to become a mess in code maintenance.=20
You have to be really careful about introducing an initializer_list=20
constructor to a class that is already initialized using uniform=20
initialization. And you have to be really careful about introducing=20
conversion operators to classes that are used as arguments in uniform=20
initialization.<br><br>Basically you need to look into your crystal ball
of choice and only use uniform initialization if you know that a class=20
will never get an initializer_list constructor.<br><br>Because of that I th=
ink we need two changes to the uniform initialization rules [...]</div></bl=
ockquote><div> </div><div>Well put. I think the current il-preference =
rule has to be looked at, if anything is to be done about this issue.<=
/div><div> </div><div>Lately, I've discovered that brace-initializatio=
n does not live up to the promise, as concerns prohibiting narrow=
ing conversions =97 at least not in the current C++11 implementations.=
Consider:</div><div> </div><div>struct S {<br> S(double, =
int);<br> S(initializer_list<int>);<br>};</div><div>S s1 =
{1.2, 1}; // Calls il-constructor (GCC and Clang warn).<br>initializer_list=
<int> il {1.2, 1}; // GCC and Clang warn; only MCC refuses.<br>S s2 {=
il};</div><div> </div><div><div>GCC 4.7.2 and Clang 3.2 compile t=
his without error (with -std=3Dc++11 -Wall -W -pedantic -O2). Microsof=
t C/C++ Optimizing Compiler Version 17.00.51025 (VS2012CTP) refuses th=
e initialization of `il`, but does not warn about narrowing in the ini=
tialization of `s1`, even at warning level 4 (/W4). <br></div></div></=
blockquote><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left=
: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div><div> </d=
iv></div><div>Without being able to trust brace-initialization not to do na=
rrowing conversions, the argument for always preferring it (which is t=
he central aim of the OP's proposal) is weakened.</div></blockquote><div><b=
r>That's an implementation issue, not a language issue. If implementers are=
getting some of the details wrong, then those are <i>compiler bugs</i>. It=
's like saying that if a compiler's variadic template implementation is scr=
ewing up template parameter packs, the language are somehow to blame.<br><b=
r>The language feature is clear on this: `S s1{1.2, 1};` cannot work with t=
he initializer_list<int> constructor. <i>Period</i>. If compilers are=
allowing it, then those <i>compilers</i> need to be fixed, not the languag=
e.<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_695_11161656.1359876562216--
.
Author: vattilah-groups@yahoo.co.uk
Date: Sun, 3 Feb 2013 00:15:09 -0800 (PST)
Raw View
------=_Part_851_11429496.1359879309663
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Thursday, 31 January 2013 22:44:27 UTC, Nicol Bolas wrote:
> [Regarding the __nolist type qualifier suggestion] What purpose does this=
=20
serve besides complicating the feature?
It was meant to be a simplification of Sebastian Gesemann's solution,=20
dispensing with the proposed special argument-dropping rule.
A type qualifier just intuitively seems more regular. Overload resolution=
=20
is currently based on types and viable conversions. The `__nolist` type=20
qualifier enables this same machinery to work for disambiguating in favour=
=20
of non-il-constructors, with a simple rule: `__nolist T` does not=20
implicitly convert to `initializer_list`, nor does an argument list in=20
which it takes part =97 the same way `"string"` and `{[...,] "string"=20
[,...]}` will not convert to `initializer_list<int>`.
> `nolist` appears to be modifying the value.
Consider it similar to `const_cast`. Rename it to `nolist_cast` if need be.
> am I supposed to do `std::vector<int>{nolist(30, 40)}`
No, `nolist` has one parameter only.
> or `std::vector<int>{nolist(30), 40}` or `std::vector<int>{nolist(30),=20
nolist(40)}`?
Any will do.
> Which element does the compiler look to to decide whether to look at=20
initializer-list constructors?
Any argument in the list with the __nolist type qualifier will prohibit the=
=20
transformation to `intializer_list`.
> [Regarding forwarding]
Forwarding will work the same way as for other type qualifiers. The type=20
qualifier will be carried around with the type. So you can meta-program=20
with the arguments and retain the information that the argument is=20
`__nolist`, the same way as for `const`.
> I don't see the point of "exploring the design space" if that exploration=
=20
doesn't actually uncover something that's better in any way. It's just=20
different.
In this case it was meant to be a simpler and more regular elaboration of=
=20
Sebastian Gesemann's proposal. It may not hold up to further scrutiny, but=
=20
I see no harm in brainstorming =97 other than risking revealing that I'm an=
=20
ignoramus, that is. :-)
Regards,
Vidar Hasfjord
--=20
---=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/?hl=3Den.
------=_Part_851_11429496.1359879309663
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
<p>On Thursday, 31 January 2013 22:44:27 UTC, Nicol Bolas wrote:<br>> [R=
egarding the __nolist type qualifier suggestion] What purpose does this ser=
ve besides complicating the feature?</p><p>It was meant to be a simplificat=
ion of Sebastian Gesemann's solution, dispensing with the proposed special =
argument-dropping rule.</p><p>A type qualifier just intuitively seems more =
regular. Overload resolution is currently based on types and viable convers=
ions. The `__nolist` type qualifier enables this same machinery to work for=
disambiguating in favour of non-il-constructors, with a simple rule: `__no=
list T` does not implicitly convert to `initializer_list`, nor does an argu=
ment list in which it takes part =97 the same way `"string"` and `{[..=
..,] "string" [,...]}` will not convert to `initializer_list<int>`.</p=
><p>> `nolist` appears to be modifying the value.</p><p>Consider it simi=
lar to `const_cast`. Rename it to `nolist_cast` if need be.</p><p>> am I=
supposed to do `std::vector<int>{nolist(30, 40)}`</p><p>No, `nolist`=
has one parameter only.</p><p>> or `std::vector<int>{nolist(30), =
40}` or `std::vector<int>{nolist(30), nolist(40)}`?</p><p>Any will do=
..</p><p>> Which element does the compiler look to to decide whether to l=
ook at initializer-list constructors?</p><p>Any argument in the list with t=
he __nolist type qualifier will prohibit the transformation to `intializer_=
list`.</p><p>> [Regarding forwarding]</p><p>Forwarding will work the sam=
e way as for other type qualifiers. The type qualifier will be carried arou=
nd with the type. So you can meta-program with the arguments and retain the=
information that the argument is `__nolist`, the same way as for `const`.<=
/p><p>> I don't see the point of "exploring the design space" if that ex=
ploration doesn't actually uncover something that's better in any way. It's=
just different.</p><p>In this case it was meant to be a simpler and more r=
egular elaboration of Sebastian Gesemann's proposal. It may not hold up to =
further scrutiny, but I see no harm in brainstorming =97 other than risking=
revealing that I'm an ignoramus, that is. :-)</p><p>Regards,<br>Vidar Hasf=
jord<br></p>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_851_11429496.1359879309663--
.
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Sun, 3 Feb 2013 00:56:16 -0800 (PST)
Raw View
------=_Part_540_13387989.1359881776571
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Sunday, February 3, 2013 8:15:16 AM UTC+4, maltes...@gmail.com wrote:
>
>
> Because of that I think we need two changes to the uniform initialization=
=20
> rules:
> 1. The change I mentioned before about dropping initializer_list=20
> preference in template code
> 2. For non-template code and fully specialized templates, an=20
> initializer_list constructor should only be preferred if no conversion is=
=20
> required.
>
Such a difference could be very surprising for some people.=20
List-initialization already has an erratic definition; making it even more=
=20
irregular would give people an additional reason to consider such=20
initialization as broken.
The code that would be broken by this was probably either not doing what=20
> you were expecting it to do anyway, or it should have been at least=20
> ambiguous to begin with, or the compiler will give you an error.
>
I doubt that such reasoning would make happy all programmers, whose code=20
would be broken.
On Sunday, February 3, 2013 10:31:42 AM UTC+4, vattila...@yahoo.co.uk wrote=
:
>
> =20
> Lately, I've discovered that brace-initialization does not live up to the=
=20
> promise, as concerns prohibiting narrowing conversions =97 at least not i=
n=20
> the current C++11 implementations. Consider:
> =20
> struct S {
> S(double, int);
> S(initializer_list<int>);
> };
> S s1 {1.2, 1}; // Calls il-constructor (GCC and Clang warn).
> initializer_list<int> il {1.2, 1}; // GCC and Clang warn; only MCC refuse=
s.
> S s2 {il};
> =20
> GCC 4.7.2 and Clang 3.2 compile this without error (with -std=3Dc++11 -Wa=
ll=20
> -W -pedantic -O2). Microsoft C/C++ Optimizing Compiler Version 17.00.5102=
5=20
> (VS2012CTP) refuses the initialization of `il`, but does not warn about=
=20
> narrowing in the initialization of `s1`, even at warning level 4 (/W4).
>
If you want errors on g++, just use -pedantic-errors instead of -pedantic.=
=20
Note also that compilers are free to translate any non-conforming code=20
successfully with issuance of a diagnotic message (a warning is a=20
diagnostic message).
--=20
---=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/?hl=3Den.
------=_Part_540_13387989.1359881776571
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: quoted-printable
On Sunday, February 3, 2013 8:15:16 AM UTC+4, maltes...@gmail.com wrote:<bl=
ockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border=
-left: 1px #ccc solid;padding-left: 1ex;"><br><div>Because of that I think =
we need two changes to the uniform initialization rules:<br>1. The change I=
mentioned before about dropping initializer_list preference in template co=
de<br>2.
For non-template code and fully specialized templates, an=20
initializer_list constructor should only be preferred if no conversion=20
is required.<br></div></blockquote><div><br>Such a difference could be=20
very surprising for some people. List-initialization already has an=20
erratic definition; making it even more irregular would give people an=20
additional reason to consider such initialization as broken.<br><br></div><=
blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bord=
er-left: 1px #ccc solid;padding-left: 1ex;"><div>The code that would be bro=
ken by this was=20
probably either not doing what you were expecting it to do anyway, or it
should have been at least ambiguous to begin with, or the compiler will gi=
ve you
an error.<br></div></blockquote><div><br>I doubt that such reasoning would=
make happy all programmers, whose code would be broken.<br></div><br>On Su=
nday, February 3, 2013 10:31:42 AM UTC+4, vattila...@yahoo.co.uk wrote:<blo=
ckquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-=
left: 1px #ccc solid;padding-left: 1ex;"><div> </div><div>Lately, I've=
discovered that brace-initialization does not live up to the promise,=
as concerns prohibiting narrowing conversions =97 at least not i=
n the current C++11 implementations. Consider:</div><div> </div><div>s=
truct S {<br> S(double, int);<br> S(initializer_lis=
t<int>);<br>};</div><div>S s1 {1.2, 1}; // Calls il-constructor (GCC =
and Clang warn).<br>initializer_list<int> il {1.2, 1}; // GCC and Cla=
ng warn; only MCC refuses.<br>S s2 {il};</div><div> </div><div><div>GC=
C 4.7.2 and Clang 3.2 compile this without error (with -std=3Dc++11 -W=
all -W -pedantic -O2). Microsoft C/C++ Optimizing Compiler Version 17.=
00.51025 (VS2012CTP) refuses the initialization of `il`, but does=
not warn about narrowing in the initialization of `s1`, even at warni=
ng level 4 (/W4).</div></div></blockquote><div><br>If you want errors on g+=
+, just use -pedantic-errors instead of -pedantic. Note also that compilers=
are free to translate any non-conforming code successfully with issuance o=
f a diagnotic message (a warning is a diagnostic message).<br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_540_13387989.1359881776571--
.
Author: vattilah-groups@yahoo.co.uk
Date: Sun, 3 Feb 2013 01:09:32 -0800 (PST)
Raw View
------=_Part_949_16271925.1359882572688
Content-Type: text/plain; charset=ISO-8859-1
On Sunday, 3 February 2013 08:56:16 UTC, Nikolay Ivchenkov wrote:
>
> [Regarding non-standard narrowing conversions] If you want errors on g++,
> just use -pedantic-errors instead of -pedantic.
>
Thanks. I note that `-pedantic-errors` has no effect on Clang 3.2 in this
case.
Regards,
Vidar Hasfjord
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_949_16271925.1359882572688
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Sunday, 3 February 2013 08:56:16 UTC, Nikolay Ivchenkov wrote:<blockquo=
te style=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color=
: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid;" cl=
ass=3D"gmail_quote"><div>[Regarding non-standard narrowing conversions] If =
you want errors on g++, just use -pedantic-errors instead of -pedantic.</di=
v></blockquote><div> </div><div>Thanks. I note that `-pedantic-er=
rors` has no effect on Clang 3.2 in this case.</div><div> </div><div>R=
egards,</div><div>Vidar Hasfjord</div><div> </div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_949_16271925.1359882572688--
.
Author: vattilah-groups@yahoo.co.uk
Date: Sun, 3 Feb 2013 01:24:59 -0800 (PST)
Raw View
------=_Part_861_29814247.1359883499751
Content-Type: text/plain; charset=ISO-8859-1
On Sunday, 3 February 2013 07:29:22 UTC, Nicol Bolas wrote:
>
> The language feature is clear on this: `S s1{1.2, 1};` cannot work with
> the initializer_list<int> constructor. *Period*. If compilers are
> allowing it, then those *compilers* need to be fixed, not the language.
>
Thanks for clarifying. That is good to know. I must admit I was a little
confused by the current state of the compilers as to the actual rules.
Regards,
Vidar Hasfjord
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_861_29814247.1359883499751
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Sunday, 3 February 2013 07:29:22 UTC, Nicol Bolas wrote:<blockquote sty=
le=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(=
204, 204, 204); border-left-width: 1px; border-left-style: solid;" class=3D=
"gmail_quote"><div>The language feature is clear on this: `S s1{1.2, 1};` c=
annot work with the initializer_list<int> constructor. <i>Period</i>.=
If compilers are allowing it, then those <i>compilers</i> need to be fixed=
, not the language.</div></blockquote><div> </div><div>Thanks for clar=
ifying. That is good to know. I must admit I was a little confused by the c=
urrent state of the compilers as to the actual rules. </div><div> </di=
v><div>Regards,</div><div>Vidar Hasfjord</div><div> </div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_861_29814247.1359883499751--
.
Author: vattilah-groups@yahoo.co.uk
Date: Sun, 3 Feb 2013 03:28:22 -0800 (PST)
Raw View
------=_Part_809_25338125.1359890902306
Content-Type: text/plain; charset=ISO-8859-1
On Saturday, 5 January 2013 04:16:32 UTC, Nicol Bolas wrote:
>
> OK, I've updated the proposal [...]
By the way, here is another surprising issue, caused by the il-preference
rule, that is not mentioned in your proposal:
template <class T>
struct S {
S(T, int);
S(initializer_list<int>);
};
S<const char*> s1 {"string", 1}; // OK: Calls non-il-constructor.
S<double> s2 {1.2, 1}; // Error: Narrowing conversion, due to il-preference.
I don't think overload resolution behaves this way in any other context.
Regards,
Vidar Hasfjord
--
---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_809_25338125.1359890902306
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Saturday, 5 January 2013 04:16:32 UTC, Nicol Bolas wrote:<blockquote st=
yle=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb=
(204, 204, 204); border-left-width: 1px; border-left-style: solid;" class=
=3D"gmail_quote">OK, I've updated the proposal [...]</blockquote><div> =
;</div><div>By the way, here is another surprising issue, caused by the il-=
preference rule, that is not mentioned in your proposal:</div><di=
v> </div><div>template <class T><br>struct S {<br> S=
(T, int);<br> S(initializer_list<int>);<br>};</div><div>S=
<const char*> s1 {"string", 1}; // OK: Calls non-il-constructor.<br>S=
<double> s2 {1.2, 1}; // Error: Narrowing conversion, due to il-prefe=
rence.<br></div><div>I don't think overload resolution behaves this wa=
y in any other context.</div><div> </div><div>Regards,</div><div>Vidar=
Hasfjord</div><div> </div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_809_25338125.1359890902306--
.