Topic: Proposal idea: std::move should not accept a
Author: Max Galkin <maksim.galkin@gmail.com>
Date: Fri, 8 May 2015 22:26:11 -0700 (PDT)
Raw View
------=_Part_3014_132473291.1431149171863
Content-Type: multipart/alternative;
boundary="----=_Part_3015_1685543545.1431149171863"
------=_Part_3015_1685543545.1431149171863
Content-Type: text/plain; charset=UTF-8
/* Just floating the idea, all and any feedback appreciated! :) --- Max */
This is a proposal to tighten the definition of std::move so that it would
not accept a const-qualified argument, and, therefore, never return a const
rvalue reference. Calling std::move with a const-qualified argument should
result in a compilation error, explaining that such a value is not movable.
Presumably, the intent of calling std::move is always to obtain a mutable
rvalue reference, never a const rvalue reference. Const rvalue references
in general only have corner case applications, e.g. by STL [1].
In all cases known to the author of the proposal, when std::move was called
with a const-qualified argument, it indicated a programmer's error. Usually
such an error does not lead to incorrect code, only to less efficient code,
because instead of a move-aware overload a copying overload of the called
function is used. But since move semantics is a performance-enabling
feature,
it seems practical to prevent such ways to accidentally misuse std::move.
This will encourage correct and efficient use and reduce the number of
"gotchas" in the standard library.
Note that this proposal is a breaking change, because it reduces the set of
acceptable programs, but, if there are indeed no benefits from calling
std::move with a const-qualified value, then all the broken cases will be
incorrectly and inefficiently applied std::move calls. Hence this change
may uncover performance defects, but it will not break any "proper" calls,
which produce mutable rvalue references.
# std::move misuse cases this change will break/prevent.
1. std::move attempting to move from a const local variable.
2. std::move attempting to move from a const member field
during move construction.
3. Accidental mistake in move constructor signature leading to
an std::move attempting to move from a const rvalue:
class X {
private:
vector<int> m_v;
public:
X(const X&& other) : m_v(std::move(other.m_v)) { };
};
# Potential new implemenation of std::move.
template <typename T> constexpr remove_reference_t<T>&&
move(T&& t) noexcept
{
static_assert(!std::is_const<remove_reference_t<T>>::value,
"std::move does not accept const-qualified arguments");
return static_cast<remove_reference_t<T>&&>(t);
}
# References
[1] CppCon 2014: Stephan Lavavej "STL Features And Implementation
Techniques", minutes 41-47:
https://www.youtube.com/watch?v=dTeKf5Oek2c&feature=youtu.be&t=2501
--
---
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/.
------=_Part_3015_1685543545.1431149171863
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>/* Just floating the idea, all and any feedback appre=
ciated! :) --- Max */</div><div><br></div><div>This is a proposal to tighte=
n the definition of std::move so that it would </div><div>not accept a=
const-qualified argument, and, therefore, never return a const</div><div>r=
value reference. Calling std::move with a const-qualified argument should&n=
bsp;</div><div>result in a compilation error, explaining that such a value =
is not movable.</div><div>Presumably, the intent of calling std::move is al=
ways to obtain a mutable </div><div>rvalue reference, never a const rv=
alue reference. Const rvalue references</div><div>in general only have corn=
er case applications, e.g. by STL [1].</div><div><br></div><div>In all case=
s known to the author of the proposal, when std::move was called </div=
><div>with a const-qualified argument, it indicated a programmer's error. U=
sually</div><div>such an error does not lead to incorrect code, only to les=
s efficient code,</div><div>because instead of a move-aware overload a copy=
ing overload of the called </div><div>function is used. But since move=
semantics is a performance-enabling feature,</div><div>it seems practical =
to prevent such ways to accidentally misuse std::move.</div><div>This will =
encourage correct and efficient use and reduce the number of </div><di=
v>"gotchas" in the standard library.</div><div><br></div><div>Note that thi=
s proposal is a breaking change, because it reduces the set of </div><=
div>acceptable programs, but, if there are indeed no benefits from calling&=
nbsp;</div><div>std::move with a const-qualified value, then all the broken=
cases will be</div><div>incorrectly and inefficiently applied std::move ca=
lls. Hence this change </div><div>may uncover performance defects, but=
it will not break any "proper" calls,</div><div>which produce mutable rval=
ue references.</div><div><br></div><div><br></div><div># std::move misuse c=
ases this change will break/prevent.</div><div><br></div><div>1. std::move =
attempting to move from a const local variable.</div><div><br></div><div>2.=
std::move attempting to move from a const member field </div><div>dur=
ing move construction.</div><div><br></div><div>3. Accidental mistake in mo=
ve constructor signature leading to</div><div>an std::move attempting to mo=
ve from a const rvalue:</div><div><br></div><div> class X {</div><div=
> private:</div><div> vector<int> m_v;</div><div><=
br></div><div> public:</div><div> X(const X&& ot=
her) : m_v(std::move(other.m_v)) { };</div><div> };</div><div><br></d=
iv><div><br></div><div><br></div><div># Potential new implemenation of std:=
:move.</div><div><br></div><div> template <typename T> constexp=
r remove_reference_t<T>&& </div><div> move(T&&=
amp; t) noexcept</div><div> {</div><div> static_assert(!=
std::is_const<remove_reference_t<T>>::value,</div><div> &=
nbsp; "std::move does not accept const-qualified arguments");</div><=
div><br></div><div> return static_cast<remove_reference_t&l=
t;T>&&>(t);</div><div> }</div><div><br></div><div><br><=
/div><div># References</div><div><br></div><div>[1] CppCon 2014: Stephan La=
vavej "STL Features And Implementation </div><div>Techniques", minutes=
41-47:</div><div>https://www.youtube.com/watch?v=3DdTeKf5Oek2c&feature=
=3Dyoutu.be&t=3D2501</div><div><br></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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_3015_1685543545.1431149171863--
------=_Part_3014_132473291.1431149171863--
.
Author: Howard Hinnant <howard.hinnant@gmail.com>
Date: Sat, 9 May 2015 10:09:57 -0500
Raw View
On May 9, 2015, at 12:26 AM, Max Galkin <maksim.galkin@gmail.com> wrote:
>=20
> Note that this proposal is a breaking change, because it reduces the set =
of=20
> acceptable programs, but, if there are indeed no benefits from calling=20
> std::move with a const-qualified value, then all the broken cases will be
> incorrectly and inefficiently applied std::move calls. Hence this change=
=20
> may uncover performance defects, but it will not break any "proper" calls=
,
> which produce mutable rvalue references.
It is indeed useful to sometimes call std::move on const objects, and have =
those objects fall back to copying (even at a performance loss). Doing oth=
erwise will effectively ban the use of const-qualified types in generic cod=
e.
Consider for example some wrapper type:
template <class T>
class my_wrapper
{
T t_;
public:
my_wrapper() =3D default;
my_wrapper(T t)
: t_(std::move(t))
{}
my_wrapper(my_wrapper&& x)
: t_(std::move(x.t_))
{
std::cout << "And do some other work\n";
}
};
template <class U, class ...T>
my_wrapper<U>
make_wrapper(T&& ...t)
{
return make_wrapper<U>(std::forward<T>(t)...);
}
For whatever reasons, the move constructor of my_wrapper can=E2=80=99t be i=
mplemented with =E2=80=9C=3D default=E2=80=9D because it needs to do some a=
dditional work. So this move constructor moves the wrapped object and does=
whatever other work is appropriate for this user-defined wrapper.
But clients often want to put const-qualified types in wrappers (I see them=
all the time in pair and tuple for example). But if we were to make this =
change, then clients will no longer be able to do this:
auto m1 =3D make_wrapper<const std::string>();
error: static_assert failed "std::move does not accept
const-qualified arguments"
static_assert(!std::is_const<remove_reference_t<_Tp>>::value,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:16:19: note: in instantiation of function template specialization =
'std::move<const std::string&>' requested here
: t_(std::move(x.t_))
^
test.cpp:32:15: note: in instantiation of member function 'my_wrapper<const=
std::string>::my_wrapper' requested here
auto m1 =3D make_wrapper<const std::string>();
^
1 error generated.
std::move has always been a *request* to move, not a demand to move. And m=
y_wrapper is a prime example of why it is only a request. Making it more t=
han a request will break large amounts of generic code. And fixing that co=
de, while possible, will make the generic code far more complex. It would =
have to manually branch on is_const (at compile time) and copy instead, obf=
uscating otherwise simple code.
Howard
--=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/.
.
Author: Max Galkin <maksim.galkin@gmail.com>
Date: Sat, 9 May 2015 12:34:27 -0700 (PDT)
Raw View
------=_Part_3602_516514625.1431200067204
Content-Type: multipart/alternative;
boundary="----=_Part_3603_932401201.1431200067204"
------=_Part_3603_932401201.1431200067204
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Thank you for the response, Howard! This is an interesting example.
I assume you meant "return my_wrapper<U>" in place of "return=20
make_wrapper<U>"
in the make_wrapper method.
I have a question about the example. Instead of the field "T t_;", maybe we=
=20
should
be using "remove_const_t<T> t_;" in this wrapper? It would make the move
constructor work even for const string. What is the benefit of passing the=
=20
const
qualifier to the type of the private field? If accessor methods need to be=
=20
exposed,
then those would expose const reference, of course.
It is possible that I'm missing something?..
Also, we could add something like "std::rvalue_cast", which would perform=
=20
the cast
unconditionally (like the current std::move does). I haven't mentioned this=
=20
option in the=20
original proposal email, because I hope that this cast, potentially=20
producing const rvalue
references, is not needed in practice...
Max
On Saturday, May 9, 2015 at 8:10:00 AM UTC-7, Howard Hinnant wrote:
>
> On May 9, 2015, at 12:26 AM, Max Galkin <maksim...@gmail.com <javascript:=
>>=20
> wrote:=20
> >=20
> > Note that this proposal is a breaking change, because it reduces the se=
t=20
> of=20
> > acceptable programs, but, if there are indeed no benefits from calling=
=20
> > std::move with a const-qualified value, then all the broken cases will=
=20
> be=20
> > incorrectly and inefficiently applied std::move calls. Hence this chang=
e=20
> > may uncover performance defects, but it will not break any "proper"=20
> calls,=20
> > which produce mutable rvalue references.=20
>
> It is indeed useful to sometimes call std::move on const objects, and hav=
e=20
> those objects fall back to copying (even at a performance loss). Doing=
=20
> otherwise will effectively ban the use of const-qualified types in generi=
c=20
> code.=20
>
> Consider for example some wrapper type:=20
>
> template <class T>=20
> class my_wrapper=20
> {=20
> T t_;=20
> public:=20
> my_wrapper() =3D default;=20
>
> my_wrapper(T t)=20
> : t_(std::move(t))=20
> {}=20
>
> my_wrapper(my_wrapper&& x)=20
> : t_(std::move(x.t_))=20
> {=20
> std::cout << "And do some other work\n";=20
> }=20
> };=20
>
> template <class U, class ...T>=20
> my_wrapper<U>=20
> make_wrapper(T&& ...t)=20
> {=20
> return make_wrapper<U>(std::forward<T>(t)...);=20
> }=20
>
> For whatever reasons, the move constructor of my_wrapper can=E2=80=99t be=
=20
> implemented with =E2=80=9C=3D default=E2=80=9D because it needs to do som=
e additional work.=20
> So this move constructor moves the wrapped object and does whatever othe=
r=20
> work is appropriate for this user-defined wrapper.=20
>
> But clients often want to put const-qualified types in wrappers (I see=20
> them all the time in pair and tuple for example). But if we were to make=
=20
> this change, then clients will no longer be able to do this:=20
>
> auto m1 =3D make_wrapper<const std::string>();=20
>
> error: static_assert failed "std::move does not accept=20
> const-qualified arguments"=20
> static_assert(!std::is_const<remove_reference_t<_Tp>>::value,=20
> ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=20
> test.cpp:16:19: note: in instantiation of function template specializatio=
n=20
> 'std::move<const std::string&>' requested here=20
> : t_(std::move(x.t_))=20
> ^=20
> test.cpp:32:15: note: in instantiation of member function=20
> 'my_wrapper<const std::string>::my_wrapper' requested here=20
> auto m1 =3D make_wrapper<const std::string>();=20
> ^=20
> 1 error generated.=20
>
> std::move has always been a *request* to move, not a demand to move. And=
=20
> my_wrapper is a prime example of why it is only a request. Making it mor=
e=20
> than a request will break large amounts of generic code. And fixing that=
=20
> code, while possible, will make the generic code far more complex. It=20
> would have to manually branch on is_const (at compile time) and copy=20
> instead, obfuscating otherwise simple code.=20
>
> Howard=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/.
------=_Part_3603_932401201.1431200067204
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Thank you for the response, Howard! This is an interesting=
example.<div><br></div><div>I assume you meant "return my_wrapper<U>=
" in place of "return make_wrapper<U>"</div><div>in the make_wrapper =
method.</div><div><br></div><div>I have a question about the example. Inste=
ad of the field "T t_;", maybe we should</div><div>be using "remove_const_t=
<T> t_;" in this wrapper? It would make the move</div><div>constructo=
r work even for const string. What is the benefit of passing the const</div=
><div>qualifier to the type of the private field? If accessor methods need =
to be exposed,</div><div>then those would expose const reference, of course=
..</div><div><br></div><div>It is possible that I'm missing something?..</di=
v><div><br></div><div>Also, we could add something like "std::rvalue_cast",=
which would perform the cast</div><div>unconditionally (like the current s=
td::move does). I haven't mentioned this option in the </div><div>orig=
inal proposal email, because I hope that this cast, potentially producing c=
onst rvalue</div><div>references, is not needed in practice...</div><div><b=
r></div><div>Max<br><br>On Saturday, May 9, 2015 at 8:10:00 AM UTC-7, Howar=
d Hinnant wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin=
-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On May 9, 2015=
, at 12:26 AM, Max Galkin <<a href=3D"javascript:" target=3D"_blank" gdf=
-obfuscated-mailto=3D"XnT5OXDaB38J" rel=3D"nofollow" onmousedown=3D"this.hr=
ef=3D'javascript:';return true;" onclick=3D"this.href=3D'javascript:';retur=
n true;">maksim...@gmail.com</a>> wrote:
<br>>=20
<br>> Note that this proposal is a breaking change, because it reduces t=
he set of=20
<br>> acceptable programs, but, if there are indeed no benefits from cal=
ling=20
<br>> std::move with a const-qualified value, then all the broken cases =
will be
<br>> incorrectly and inefficiently applied std::move calls. Hence this =
change=20
<br>> may uncover performance defects, but it will not break any "proper=
" calls,
<br>> which produce mutable rvalue references.
<br>
<br>It is indeed useful to sometimes call std::move on const objects, and h=
ave those objects fall back to copying (even at a performance loss). =
Doing otherwise will effectively ban the use of const-qualified types in ge=
neric code.
<br>
<br>Consider for example some wrapper type:
<br>
<br> template <class T>
<br> class my_wrapper
<br> {
<br> T t_;
<br> public:
<br> my_wrapper() =3D default;
<br>
<br> my_wrapper(T t)
<br> : t_(std::move(t))
<br> {}
<br>
<br> my_wrapper(my_wrapper&& x)
<br> : t_(std::move(x.t_))
<br> {
<br> std::cout << "And do so=
me other work\n";
<br> }
<br> };
<br>
<br> template <class U, class ...T>
<br> my_wrapper<U>
<br> make_wrapper(T&& ...t)
<br> {
<br> return make_wrapper<U>(std::forward&l=
t;<wbr>T>(t)...);
<br> }
<br>
<br>For whatever reasons, the move constructor of my_wrapper can=E2=80=99t =
be implemented with =E2=80=9C=3D default=E2=80=9D because it needs to do so=
me additional work. So this move constructor moves the wrapped object=
and does whatever other work is appropriate for this user-defined wrapper.
<br>
<br>But clients often want to put const-qualified types in wrappers (I see =
them all the time in pair and tuple for example). But if we were to m=
ake this change, then clients will no longer be able to do this:
<br>
<br> auto m1 =3D make_wrapper<const std::string>();
<br>
<br>error: static_assert failed "std::move does not accept
<br> const-qualified arguments"
<br>static_assert(!std::is_const<<wbr>remove_reference_t<_Tp>>:=
:<wbr>value,
<br>^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~=
~~~<wbr>~~~~~~~~~~~~~~~~
<br>test.cpp:16:19: note: in instantiation of function template specializat=
ion 'std::move<const std::string&>' requested here
<br> : t_(std::move(x.t_))
<br> ^
<br>test.cpp:32:15: note: in instantiation of member function 'my_wrapper&l=
t;const std::string>::my_wrapper' requested here
<br> auto m1 =3D make_wrapper<const std::string>();
<br> ^
<br>1 error generated.
<br>
<br>std::move has always been a *request* to move, not a demand to move. &n=
bsp;And my_wrapper is a prime example of why it is only a request. Ma=
king it more than a request will break large amounts of generic code.  =
;And fixing that code, while possible, will make the generic code far more =
complex. It would have to manually branch on is_const (at compile tim=
e) and copy instead, obfuscating otherwise simple code.
<br>
<br>Howard
<br>
<br></blockquote></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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_3603_932401201.1431200067204--
------=_Part_3602_516514625.1431200067204--
.
Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
Date: Sat, 9 May 2015 18:15:08 -0700 (PDT)
Raw View
------=_Part_3811_37362952.1431220509107
Content-Type: multipart/alternative;
boundary="----=_Part_3812_893909340.1431220509107"
------=_Part_3812_893909340.1431220509107
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Saturday, May 9, 2015 at 12:34:27 PM UTC-7, Max Galkin wrote:
>
>
> I have a question about the example. Instead of the field "T t_;", maybe=
=20
> we should
>
be using "remove_const_t<T> t_;" in this wrapper? It would make the move
> constructor work even for const string. What is the benefit of passing th=
e=20
> const
> qualifier to the type of the private field?
>
Well, you're basically proposing that every writer of generic code=20
complicate *their* code, just so that *you* can detect one particular class=
=20
of uncommon typographical errors. There's a huge (and hopefully obvious)=20
benefit to *not* force everyone to write remove_const_t<T> when they could=
=20
just be writing T. And there is just a *ton* of code out there right now=20
just writing T; I'm sure you couldn't force everyone to change it if you=20
tried.
As Howard says:
> std::move has always been a *request* to move, not a demand to move. And=
=20
my_wrapper is a prime example of why it is only a request. Making it more=
=20
than a request will break large amounts of generic code. And fixing that=
=20
code, while possible, will make the generic code far more complex. It=20
would have to manually branch on is_const (at compile time) and copy=20
instead, obfuscating otherwise simple code.
=20
> Also, we could add something like "std::rvalue_cast", which would perform=
=20
> the cast
> unconditionally (like the current std::move does). I haven't mentioned=20
> this option in the=20
> original proposal email, because I hope that this cast, potentially=20
> producing const rvalue
> references, is not needed in practice...
>
Current std::move already has the semantics that you propose for=20
std::rvalue_cast, so let's keep using std::move for that.
The question is, do we need another identifier that means "like move but=20
only for non-const-qualified types"?
I've found that a good practice when thinking about const is to remember=20
that *const is not the only type-qualifier in C++*! Therefore, it basically=
=20
never makes sense to propose anything re: const if you are not equally=20
prepared to propose the same thing re: volatile.
http://en.cppreference.com/w/cpp/types/remove_cv
http://en.cppreference.com/w/cpp/types/is_const#See_also
=E2=80=93Arthur
--=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/.
------=_Part_3812_893909340.1431220509107
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Saturday, May 9, 2015 at 12:34:27 PM UTC-7, Max Galkin =
wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8=
ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><b=
r></div><div>I have a question about the example. Instead of the field "T t=
_;", maybe we should</div></div></blockquote><blockquote class=3D"gmail_quo=
te" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddi=
ng-left: 1ex;"><div dir=3D"ltr"><div>be using "remove_const_t<T> t_;"=
in this wrapper? It would make the move</div><div>constructor work even fo=
r const string. What is the benefit of passing the const</div><div>qualifie=
r to the type of the private field?</div></div></blockquote><div><br></div>=
<div>Well, you're basically proposing that every writer of generic code com=
plicate <i>their</i> code, just so that <i>you</i> can detect one particula=
r class of uncommon typographical errors. There's a huge (and hopefull=
y obvious) benefit to <i>not</i> force everyone to write <font face=3D"cour=
ier new, monospace">remove_const_t<T></font> when they could just be =
writing <font face=3D"courier new, monospace">T</font>. And there is just a=
<i>ton</i> of code out there right now just writing <font face=3D"courier =
new, monospace">T</font>; I'm sure you couldn't force everyone to change it=
if you tried.</div><div><br></div><div><div>As Howard says:</div><div>>=
std::move has always been a *request* to move, not a demand to move.  =
;And my_wrapper is a prime example of why it is only a request. Makin=
g it more than a request will break large amounts of generic code. An=
d fixing that code, while possible, will make the generic code far more com=
plex. It would have to manually branch on is_const (at compile time) =
and copy instead, obfuscating otherwise simple code.</div><div><br></div><b=
lockquote 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></div></blockquote><=
/div><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=
dir=3D"ltr"><div>Also, we could add something like "std::rvalue_cast", whi=
ch would perform the cast<br></div><div>unconditionally (like the current s=
td::move does). I haven't mentioned this option in the </div><div>orig=
inal proposal email, because I hope that this cast, potentially producing c=
onst rvalue</div><div>references, is not needed in practice...</div></div><=
/blockquote><div><br></div><div>Current <font face=3D"courier new, monospac=
e">std::move</font> already has the semantics that you propose for <font fa=
ce=3D"courier new, monospace">std::rvalue_cast</font>, so let's keep using =
<font face=3D"courier new, monospace">std::move</font> for that.</div>=
<div>The question is, do we need another identifier that means "like <font =
face=3D"courier new, monospace">move</font> but only for non-const-qualifie=
d types"?</div><div><br></div><div>I've found that a good practice when thi=
nking about <font face=3D"courier new, monospace">const</font> is to rememb=
er that <b><font face=3D"courier new, monospace">const</font> is not the on=
ly type-qualifier in C++</b>! Therefore, it basically never makes sense to =
propose anything re: <font face=3D"courier new, monospace">const</font> if =
you are not equally prepared to propose the same thing re: <font face=3D"co=
urier new, monospace">volatile</font>.</div><div><a href=3D"http://en.cppre=
ference.com/w/cpp/types/remove_cv">http://en.cppreference.com/w/cpp/types/r=
emove_cv</a><br></div><div><a href=3D"http://en.cppreference.com/w/cpp/type=
s/is_const#See_also">http://en.cppreference.com/w/cpp/types/is_const#See_al=
so</a><br></div><div><br></div><div>=E2=80=93Arthur</div><div><br></div></d=
iv>
<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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_3812_893909340.1431220509107--
------=_Part_3811_37362952.1431220509107--
.
Author: David Krauss <potswa@mac.com>
Date: Sun, 10 May 2015 10:54:02 +0800
Raw View
--Apple-Mail=_CAB9D877-B698-493F-9C73-38A6EA1CAF5E
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8
> On 2015=E2=80=9305=E2=80=9309, at 1:26 PM, Max Galkin <maksim.galkin@gmai=
l.com> wrote:
>=20
> Const rvalue references
> in general only have corner case applications, e.g. by STL [1].
>=20
> In all cases known to the author of the proposal, when std::move was call=
ed=20
> with a const-qualified argument, it indicated a programmer's error.=20
A const rvalue reference will usually initialize a const lvalue reference. =
This doesn=E2=80=99t indicate an error.
The source of the performance issue you=E2=80=99re trying to detect isn=E2=
=80=99t usually at the move(const_value) at all, but somewhere upstream whe=
re someone forgot to move and the object got bound to a const & reference i=
nstead. If, in the troublesome context, the move really wasn=E2=80=99t forg=
otten but actually unsafe (and you can=E2=80=99t assume it is), your propos=
al would take an innocuous corner case and make it intractable.
A generic function working with both const and non-const sequences can indi=
scriminately move and get correct, optimal behavior in both cases. (There a=
re classes with movably mutable members, but they should work either way an=
d the intent is ambiguous.) My proposal N4166, (to be revised soon) provide=
s new std::initializer_list types with non-const (movable) access, and the =
generic usage style is just to ask for move and take what you get.
Anytime you pass an expression of const class type to a forwarding referenc=
e, it will generate a const rvalue reference. Do you propose to deprecate c=
onst prvalues in general?
> Usually
> such an error does not lead to incorrect code, only to less efficient cod=
e,
> because instead of a move-aware overload a copying overload of the called=
=20
> function is used.
There are several non-breaking solutions:
1. Implement your proposal in your own codebase. Usage experience will help=
if you still feel it to be worthy of standardization.
2. static_assert the non-constness in specific instances of calls to move, =
or when receiving rvalue references by forwarding.
3. Delete the const move constructor of the offending classes: T::T(T const=
&&) =3D delete;.
--=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/.
--Apple-Mail=_CAB9D877-B698-493F-9C73-38A6EA1CAF5E
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8
<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dutf-8"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-mode: s=
pace; -webkit-line-break: after-white-space;" class=3D""><div class=3D""><b=
r class=3D""></div><blockquote type=3D"cite" class=3D""><div class=3D"">On =
2015=E2=80=9305=E2=80=9309, at 1:26 PM, Max Galkin <<a href=3D"mailto:ma=
ksim.galkin@gmail.com" class=3D"">maksim.galkin@gmail.com</a>> wrote:</d=
iv><br class=3D"Apple-interchange-newline"><div class=3D""><div class=3D"">=
Const rvalue references</div><div class=3D"">in general only have corner ca=
se applications, e.g. by STL [1].</div></div></blockquote><blockquote type=
=3D"cite" class=3D""><br class=3D""></blockquote><blockquote type=3D"cite" =
class=3D""><div class=3D""><div class=3D"">In all cases known to the author=
of the proposal, when std::move was called </div></div></blockquote><=
blockquote type=3D"cite" class=3D""><div class=3D""><div class=3D"">with a =
const-qualified argument, it indicated a programmer's error. </div></d=
iv></blockquote><div class=3D""><div class=3D""><div class=3D""><br class=
=3D""></div></div></div><div class=3D"">A const rvalue reference will usual=
ly initialize a const lvalue reference. This doesn=E2=80=99t indicate an er=
ror.</div><div class=3D""><br class=3D""></div><div class=3D""><div class=
=3D"">The source of the performance issue you=E2=80=99re trying to detect i=
sn=E2=80=99t usually at the <font face=3D"Courier" class=3D"">move(con=
st_value)</font> at all, but somewhere upstream where someone forgot t=
o <font face=3D"Courier" class=3D"">move</font> and the object go=
t bound to a <font face=3D"Courier" class=3D"">const &</font> =
;reference instead. If, in the troublesome context, the <font face=3D"=
Courier" class=3D"">move</font> really wasn=E2=80=99t forgotten but ac=
tually unsafe (and you can=E2=80=99t assume it is), your proposal would tak=
e an innocuous corner case and make it intractable.</div><div class=3D""><b=
r class=3D""></div></div><div class=3D"">A generic function working with bo=
th const and non-const sequences can indiscriminately move and get correct,=
optimal behavior in both cases. (There are classes with movably mutable me=
mbers, but they should work either way and the intent is ambiguous.) My pro=
posal N4166, (to be revised soon) provides new <font face=3D"Courier" =
class=3D"">std::initializer_list</font> types with non-const (movable)=
access, and the generic usage style is just to ask for <font face=3D"Couri=
er" class=3D"">move</font> and take what you get.</div><div class=3D""><br =
class=3D""></div><div class=3D"">Anytime you pass an expression of const cl=
ass type to a forwarding reference, it will generate a const rvalue referen=
ce. Do you propose to deprecate const prvalues in general?</div><div class=
=3D""><br class=3D""></div><div class=3D""><blockquote type=3D"cite" class=
=3D""><div class=3D"">Usually</div><div class=3D""><div class=3D"">such an =
error does not lead to incorrect code, only to less efficient code,</div><d=
iv class=3D"">because instead of a move-aware overload a copying overload o=
f the called </div><div class=3D"">function is used.</div></div></bloc=
kquote><div class=3D""><div class=3D""><div class=3D""><br class=3D""></div=
></div></div><div class=3D"">There are several non-breaking solutions:</div=
><div class=3D""><br class=3D""></div><div class=3D"">1. Implement your pro=
posal in your own codebase. Usage experience will help if you still feel it=
to be worthy of standardization.</div><div class=3D"">2. <font face=3D"Cou=
rier" class=3D"">static_assert</font> the non-constness in specific instanc=
es of calls to <font face=3D"Courier" class=3D"">move</font>, or when =
receiving rvalue references by forwarding.</div><div class=3D"">3. Delete t=
he const move constructor of the offending classes: <font face=3D"Courier" =
class=3D"">T::T(T const &&) =3D delete;</font>.</div></div></body><=
/html>
<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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--Apple-Mail=_CAB9D877-B698-493F-9C73-38A6EA1CAF5E--
.
Author: Max Galkin <maksim.galkin@gmail.com>
Date: Sat, 9 May 2015 21:37:46 -0700 (PDT)
Raw View
------=_Part_3931_435174946.1431232666821
Content-Type: multipart/alternative;
boundary="----=_Part_3932_1803499387.1431232666821"
------=_Part_3932_1803499387.1431232666821
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Thanks for taking time to review the idea, Arthur!
> Well, you're basically proposing that every writer of generic code=20
complicate *their* code, just so that *you* can detect one particular class=
=20
of uncommon typographical errors.
I'm not proposing this to detect problems in *my* code,=20
personally I can just use this utility function directly :)
I'm proposing this because I think it closes a "gotcha" in the library,
where a copy is made instead of the move implicitly in some subtle cases
which I'm afraid are usually unnoticed.
Which is better for writers of generic code: a function that silently=20
chooses
a less efficient approach depending on the constness of the argument,=20
or a function that always produces a mutable rvalue reference, and reports=
=20
an error
when it can't, so that the writer can take corrective action depending on
the purpose of the library -- either get rid of the constness, or change th=
e
"move" to uncoditional cast?
It can be a new identifier, not "std::move", but shouldn't library writers
prefer to use the more restrictive identifier as their default option anywa=
y
to catch the errors early on and at compile time?
> There's a huge (and hopefully obvious) benefit to *not* force everyone to=
=20
write remove_const_t<T> when they could just be writing T.=20
If they just write "T" in that wrapper example, and instantiate with "const=
=20
string",=20
the move constructor will _copy_ the private string, because the field will=
=20
be of type "const string".
If they write "remove_const_t<T>", the move constructor will _move_ the=20
private "string".
Difference in wrapper performance may be significant!
Please correct me, I must be wrong, because it is not obvious to me, what=
=20
is the benefit of just writing T instead of remove_const_t<T>.
> As Howard says:
>> std::move has always been a *request* to move, not a demand to move.=20
And my_wrapper is a prime example of why it is only a request. Making it=
=20
more than a request will break large amounts of generic code. And fixing=
=20
that code, while possible, will make the generic code far more complex. It=
=20
would have to manually branch on is_const (at compile time) and copy=20
instead, obfuscating otherwise simple code.
I undestand the current implementation is a *request*.
I don't understand why is *request* better than demand.
For "my_wrapper" see the above explanation.=20
You don't need to branch on "is_const" in this case...
> I've found that a good practice when thinking about const is to remember=
=20
that *const is not the only type-qualifier in C++*! Therefore, it basically=
=20
never makes sense to propose anything re: const if you are not equally=20
prepared to propose the same thing re: volatile.
One can move volatile-qualified objects, but can't move const-qualified=20
objects, so there is already an asymmetry by design...
I have examined the 2 pages you linked and couldn't find any clarification=
=20
there...
So far it seems to me that "volatile" isn't really interacting with move in=
=20
any interesting way... Can you elaborate on how "volatile" could be=20
relevant here?
Thanks!
Max
On Saturday, May 9, 2015 at 6:15:09 PM UTC-7, Arthur O'Dwyer wrote:
>
> On Saturday, May 9, 2015 at 12:34:27 PM UTC-7, Max Galkin wrote:
>>
>>
>> I have a question about the example. Instead of the field "T t_;", maybe=
=20
>> we should
>>
> be using "remove_const_t<T> t_;" in this wrapper? It would make the move
>> constructor work even for const string. What is the benefit of passing=
=20
>> the const
>> qualifier to the type of the private field?
>>
>
> Well, you're basically proposing that every writer of generic code=20
> complicate *their* code, just so that *you* can detect one particular=20
> class of uncommon typographical errors. There's a huge (and hopefully=20
> obvious) benefit to *not* force everyone to write remove_const_t<T> when=
=20
> they could just be writing T. And there is just a *ton* of code out there=
=20
> right now just writing T; I'm sure you couldn't force everyone to change=
=20
> it if you tried.
>
> As Howard says:
> > std::move has always been a *request* to move, not a demand to move.=20
> And my_wrapper is a prime example of why it is only a request. Making i=
t=20
> more than a request will break large amounts of generic code. And fixing=
=20
> that code, while possible, will make the generic code far more complex. =
It=20
> would have to manually branch on is_const (at compile time) and copy=20
> instead, obfuscating otherwise simple code.
>
> =20
>
>> Also, we could add something like "std::rvalue_cast", which would perfor=
m=20
>> the cast
>> unconditionally (like the current std::move does). I haven't mentioned=
=20
>> this option in the=20
>> original proposal email, because I hope that this cast, potentially=20
>> producing const rvalue
>> references, is not needed in practice...
>>
>
> Current std::move already has the semantics that you propose for=20
> std::rvalue_cast, so let's keep using std::move for that.
> The question is, do we need another identifier that means "like move but=
=20
> only for non-const-qualified types"?
>
> I've found that a good practice when thinking about const is to remember=
=20
> that *const is not the only type-qualifier in C++*! Therefore, it=20
> basically never makes sense to propose anything re: const if you are not=
=20
> equally prepared to propose the same thing re: volatile.
> http://en.cppreference.com/w/cpp/types/remove_cv
> http://en.cppreference.com/w/cpp/types/is_const#See_also
>
> =E2=80=93Arthur
>
>
--=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/.
------=_Part_3932_1803499387.1431232666821
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>Thanks for taking time to review the idea, Arthur!</d=
iv><div><br></div><div><br></div><div>> Well, you're basically proposing=
that every writer of generic code complicate <i>their</i> code, =
just so that <i>you</i> can detect one particular class of uncomm=
on typographical errors.</div><div><br></div><div>I'm not proposing this to=
detect problems in *my* code, </div><div>personally I can just use th=
is utility function directly :)</div><div><br></div><div>I'm proposing this=
because I think it closes a "gotcha" in the library,</div><div>where a cop=
y is made instead of the move implicitly in some subtle cases</div><div>whi=
ch I'm afraid are usually unnoticed.</div><div><br></div><div>Which is bett=
er for writers of generic code: a function that silently chooses</div><div>=
a less efficient approach depending on the constness of the argument, =
</div><div>or a function that always produces a mutable rvalue reference, a=
nd reports an error</div><div>when it can't, so that the writer can take co=
rrective action depending on</div><div>the purpose of the library -- either=
get rid of the constness, or change the</div><div>"move" to uncoditional c=
ast?</div><div><br></div><div>It can be a new identifier, not "std::move", =
but shouldn't library writers</div><div>prefer to use the more restrictive =
identifier as their default option anyway</div><div>to catch the errors ear=
ly on and at compile time?</div><div><br></div><div><br></div><div><div>>=
; There's a huge (and hopefully obvious) benefit to <i>not</i>&nb=
sp;force everyone to write <font face=3D"courier new, monospace">remov=
e_const_t<T></font> when they could just be writing <font f=
ace=3D"courier new, monospace">T</font>. </div><div><br></div><div>If =
they just write "T" in that wrapper example, and instantiate with "const st=
ring", <br></div><div>the move constructor will _copy_ the private str=
ing, because the field will be of type "const string".</div><div>If they wr=
ite "<span style=3D"font-family: 'courier new', monospace;">remove_const_t&=
lt;T></span>", the move constructor will _move_ the private "string".<br=
></div><div>Difference in wrapper performance may be significant!</div><div=
>Please correct me, I must be wrong, because it is not obvious to me, what =
is the benefit of just writing T instead of <span style=3D"font-family=
: 'courier new', monospace;">remove_const_t<T>.</span></div><div><br>=
</div><div><div><div>> As Howard says:</div><div>>> std::move has =
always been a *request* to move, not a demand to move. And my_wrapper=
is a prime example of why it is only a request. Making it more than =
a request will break large amounts of generic code. And fixing that c=
ode, while possible, will make the generic code far more complex. It =
would have to manually branch on is_const (at compile time) and copy instea=
d, obfuscating otherwise simple code.</div></div><div><br></div><div>I unde=
stand the current implementation is a *request*.</div><div>I don't understa=
nd why is *request* better than demand.</div><div>For "my_wrapper" see the =
above explanation. </div><div>You don't need to branch on "is_const" i=
n this case...</div><div><br></div><div>> I've found that a good practic=
e when thinking about <font face=3D"courier new, monospace">const</fon=
t> is to remember that <b><font face=3D"courier new, monospace">c=
onst</font> is not the only type-qualifier in C++</b>! Therefore, it b=
asically never makes sense to propose anything re: <font face=3D"couri=
er new, monospace">const</font> if you are not equally prepared to pro=
pose the same thing re: <font face=3D"courier new, monospace">volatile=
</font>.<br></div><div><br></div><div>One can move volatile-qualified objec=
ts, but can't move const-qualified objects, so there is already an asymmetr=
y by design...</div><div>I have examined the 2 pages you linked and couldn'=
t find any clarification there...<br></div><div>So far it seems to me that =
"volatile" isn't really interacting with move in any interesting way... Can=
you elaborate on how "volatile" could be relevant here?</div><div><br></di=
v><div><br></div><div>Thanks!</div><div>Max</div><div><br></div><div><br></=
div><div>On Saturday, May 9, 2015 at 6:15:09 PM UTC-7, Arthur O'Dwyer wrote=
:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bo=
rder-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">On Saturday,=
May 9, 2015 at 12:34:27 PM UTC-7, Max Galkin wrote:<blockquote class=3D"gm=
ail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;p=
adding-left:1ex"><div dir=3D"ltr"><div><br></div><div>I have a question abo=
ut the example. Instead of the field "T t_;", maybe we should</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 dir=3D"ltr"><div>be=
using "remove_const_t<T> t_;" in this wrapper? It would make the mov=
e</div><div>constructor work even for const string. What is the benefit of =
passing the const</div><div>qualifier to the type of the private field?</di=
v></div></blockquote><div><br></div><div>Well, you're basically proposing t=
hat every writer of generic code complicate <i>their</i> code, just so that=
<i>you</i> can detect one particular class of uncommon typographical error=
s. There's a huge (and hopefully obvious) benefit to <i>not</i> force =
everyone to write <font face=3D"courier new, monospace">remove_const_t<T=
></font> when they could just be writing <font face=3D"courier new, mono=
space">T</font>. And there is just a <i>ton</i> of code out there right now=
just writing <font face=3D"courier new, monospace">T</font>; I'm sure you =
couldn't force everyone to change it if you tried.</div><div><br></div><div=
><div>As Howard says:</div><div>> std::move has always been a *request* =
to move, not a demand to move. And my_wrapper is a prime example of w=
hy it is only a request. Making it more than a request will break lar=
ge amounts of generic code. And fixing that code, while possible, wil=
l make the generic code far more complex. It would have to manually b=
ranch on is_const (at compile time) and copy instead, obfuscating otherwise=
simple code.</div><div><br></div><blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(20=
4,204,204);border-left-style:solid;padding-left:1ex"><div dir=3D"ltr"><div>=
</div></div></blockquote></div><div> <br></div><blockquote class=3D"gm=
ail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;p=
adding-left:1ex"><div dir=3D"ltr"><div>Also, we could add something like "s=
td::rvalue_cast", which would perform the cast<br></div><div>unconditionall=
y (like the current std::move does). I haven't mentioned this option in the=
</div><div>original proposal email, because I hope that this cast, po=
tentially producing const rvalue</div><div>references, is not needed in pra=
ctice...</div></div></blockquote><div><br></div><div>Current <font face=3D"=
courier new, monospace">std::move</font> already has the semantics that you=
propose for <font face=3D"courier new, monospace">std::rvalue_cast</font>,=
so let's keep using <font face=3D"courier new, monospace">std::move</font>=
for that.</div><div>The question is, do we need another identifier th=
at means "like <font face=3D"courier new, monospace">move</font> but only f=
or non-const-qualified types"?</div><div><br></div><div>I've found that a g=
ood practice when thinking about <font face=3D"courier new, monospace">cons=
t</font> is to remember that <b><font face=3D"courier new, monospace">const=
</font> is not the only type-qualifier in C++</b>! Therefore, it basically =
never makes sense to propose anything re: <font face=3D"courier new, monosp=
ace">const</font> if you are not equally prepared to propose the same thing=
re: <font face=3D"courier new, monospace">volatile</font>.</div><div><a hr=
ef=3D"http://en.cppreference.com/w/cpp/types/remove_cv" target=3D"_blank" r=
el=3D"nofollow" onmousedown=3D"this.href=3D'http://www.google.com/url?q\75h=
ttp%3A%2F%2Fen.cppreference.com%2Fw%2Fcpp%2Ftypes%2Fremove_cv\46sa\75D\46sn=
tz\0751\46usg\75AFQjCNF0hjH13vcX-yYlkOvRPN-kLHG1Ow';return true;" onclick=
=3D"this.href=3D'http://www.google.com/url?q\75http%3A%2F%2Fen.cppreference=
..com%2Fw%2Fcpp%2Ftypes%2Fremove_cv\46sa\75D\46sntz\0751\46usg\75AFQjCNF0hjH=
13vcX-yYlkOvRPN-kLHG1Ow';return true;">http://en.cppreference.com/w/<wbr>cp=
p/types/remove_cv</a><br></div><div><a href=3D"http://en.cppreference.com/w=
/cpp/types/is_const#See_also" target=3D"_blank" rel=3D"nofollow" onmousedow=
n=3D"this.href=3D'http://www.google.com/url?q\75http%3A%2F%2Fen.cppreferenc=
e.com%2Fw%2Fcpp%2Ftypes%2Fis_const%23See_also\46sa\75D\46sntz\0751\46usg\75=
AFQjCNHG2w9f6y0pg8TRYy9sa3XzoYrHFg';return true;" onclick=3D"this.href=3D'h=
ttp://www.google.com/url?q\75http%3A%2F%2Fen.cppreference.com%2Fw%2Fcpp%2Ft=
ypes%2Fis_const%23See_also\46sa\75D\46sntz\0751\46usg\75AFQjCNHG2w9f6y0pg8T=
RYy9sa3XzoYrHFg';return true;">http://en.cppreference.com/w/<wbr>cpp/types/=
is_const#See_also</a><br></div><div><br></div><div>=E2=80=93Arthur</div><di=
v><br></div></div></blockquote></div></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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_3932_1803499387.1431232666821--
------=_Part_3931_435174946.1431232666821--
.
Author: Max Galkin <maksim.galkin@gmail.com>
Date: Sun, 10 May 2015 00:06:59 -0700 (PDT)
Raw View
------=_Part_4301_1331019458.1431241619335
Content-Type: multipart/alternative;
boundary="----=_Part_4302_106879807.1431241619335"
------=_Part_4302_106879807.1431241619335
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Thank you for reviewing the idea, David!
> A const rvalue reference will usually initialize a const lvalue=20
reference. This doesn=E2=80=99t indicate an error.
> The source of the performance issue you=E2=80=99re trying to detect isn=
=E2=80=99t usually=20
at the move(const_value) at all, but somewhere upstream where someone=20
forgot to move and the object got bound to a const & reference instead. If,=
=20
in the troublesome context, the move really wasn=E2=80=99t forgotten but ac=
tually=20
unsafe (and you can=E2=80=99t assume it is), your proposal would take an in=
nocuous=20
corner case and make it intractable.
In what context is this happening, the situation you're describing?
1. If you're in a non-generic method, and you're trying to move a variable=
=20
declared as "const&" then what are you trying to achieve? It is just=20
misleading and has no effect.
2. If you are in a generic method using a universal reference, then you=20
should probably be calling std::forward instead of std:move.
3. If you're inside the move constructor intialization and some field is=20
const, you can just initialize directly, without calling std::move() on it.
4. I can really only think of a case such as=20
template<class T>=20
void f1(T& t)
{=20
f2(std::move(t));=20
}
called with a const object... Could it maybe be turned into taking a=20
universal reference and forwarding...
What would be a real application for this?.. Or for an uncoditional move of=
=20
a forwarding reference?..
I'll think about it :)
However, in any case, nothing becomes intractable with this proposal. An=20
unconditional cast to T&& is always available...=20
The question is, should the unconditional cast be the default, or should a=
=20
more restricitve approach be preferred, and only
switch to an unconditional cast, if the restrictive move is not=20
appropriate...
> A generic function working with both const and non-const sequences can=20
indiscriminately move and get correct, optimal behavior in both cases.=20
(There are classes with movably mutable members, but they should work=20
either way and the intent is ambiguous.) My proposal N4166, (to be revised=
=20
soon) provides new std::initializer_list types with non-const (movable)=20
access, and the generic usage style is just to ask for move and take what=
=20
you get.
Are you referring to this example below from N4166?
template< typename t > // t is foo or foo &&.
void generic(std::initializer_list< t > seq) {
for (auto && f : seq) { // f is const or modifiable.
smth(std::move(f)); // Move is defeated by const.
}
}
Well, this is interesting... :)
I understand that you are relying on the implementation detail that=20
initializer_list=20
sequence always has either const or effectively-rvalue elements and never=
=20
just lvalues
since one can't make initializer_list<T&> and pass it to 2 different=20
objects...
To convince myself that this method is safe I had to review the=20
declarations of
both classes and hope that these implementation details will not change...
Maybe the iterator type could be a wrapper that would return a T&& on=20
operator*
and then the usage would be to std::forward<decltype(f)>(f)?=20
Would it make more sense?
Thanks!
Max
On Saturday, May 9, 2015 at 7:54:10 PM UTC-7, David Krauss wrote:
>
>
> On 2015=E2=80=9305=E2=80=9309, at 1:26 PM, Max Galkin <maksim...@gmail.co=
m <javascript:>>=20
> wrote:
>
> Const rvalue references
> in general only have corner case applications, e.g. by STL [1].
>
>
> In all cases known to the author of the proposal, when std::move was=20
> called=20
>
> with a const-qualified argument, it indicated a programmer's error.=20
>
>
> A const rvalue reference will usually initialize a const lvalue reference=
..=20
> This doesn=E2=80=99t indicate an error.
>
> The source of the performance issue you=E2=80=99re trying to detect isn=
=E2=80=99t usually=20
> at the move(const_value) at all, but somewhere upstream where someone=20
> forgot to move and the object got bound to a const & reference instead.=
=20
> If, in the troublesome context, the move really wasn=E2=80=99t forgotten =
but=20
> actually unsafe (and you can=E2=80=99t assume it is), your proposal would=
take an=20
> innocuous corner case and make it intractable.
>
> A generic function working with both const and non-const sequences can=20
> indiscriminately move and get correct, optimal behavior in both cases.=20
> (There are classes with movably mutable members, but they should work=20
> either way and the intent is ambiguous.) My proposal N4166, (to be revise=
d=20
> soon) provides new std::initializer_list types with non-const (movable)=
=20
> access, and the generic usage style is just to ask for move and take what=
=20
> you get.
>
> Anytime you pass an expression of const class type to a forwarding=20
> reference, it will generate a const rvalue reference. Do you propose to=
=20
> deprecate const prvalues in general?
>
> Usually
> such an error does not lead to incorrect code, only to less efficient cod=
e,
> because instead of a move-aware overload a copying overload of the called=
=20
> function is used.
>
>
> There are several non-breaking solutions:
>
> 1. Implement your proposal in your own codebase. Usage experience will=20
> help if you still feel it to be worthy of standardization.
> 2. static_assert the non-constness in specific instances of calls to move=
,=20
> or when receiving rvalue references by forwarding.
> 3. Delete the const move constructor of the offending classes: T::T(T=20
> const &&) =3D delete;.
>
--=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/.
------=_Part_4302_106879807.1431241619335
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Thank you for reviewing the idea, David!<div><br></div><di=
v><div>> A const rvalue reference will usually initialize a const lvalue=
reference. This doesn=E2=80=99t indicate an error.</div><div>> The sour=
ce of the performance issue you=E2=80=99re trying to detect isn=E2=80=99t u=
sually at the <font face=3D"Courier">move(const_value)</font> at =
all, but somewhere upstream where someone forgot to <font face=3D"Cour=
ier">move</font> and the object got bound to a <font face=3D"Cour=
ier">const &</font> reference instead. If, in the troublesome cont=
ext, the <font face=3D"Courier">move</font> really wasn=E2=80=99t=
forgotten but actually unsafe (and you can=E2=80=99t assume it is), your p=
roposal would take an innocuous corner case and make it intractable.<br></d=
iv></div><div><br></div><div>In what context is this happening, the situati=
on you're describing?</div><div>1. If you're in a non-generic method, and y=
ou're trying to move a variable declared as "const&" then what are you =
trying to achieve? It is just misleading and has no effect.</div><div>2. If=
you are in a generic method using a universal reference, then you should p=
robably be calling std::forward instead of std:move.</div><div>3. If you're=
inside the move constructor intialization and some field is const, you can=
just initialize directly, without calling std::move() on it.</div><div>4. =
I can really only think of a case such as </div><div><br></div><div>te=
mplate<class T> </div><div>void f1(T& t)</div><div>{ </=
div><div> f2(std::move(t)); </div><div>}<br></div><div><br=
></div><div>called with a const object... Could it maybe be turned into tak=
ing a universal reference and forwarding...</div><div>What would be a real =
application for this?.. Or for an uncoditional move of a forwarding referen=
ce?..</div><div>I'll think about it :)<br></div><div><br></div><div>However=
, in any case, nothing becomes intractable with this proposal. An unconditi=
onal cast to T&& is always available... </div><div>The questio=
n is, should the unconditional cast be the default, or should a more restri=
citve approach be preferred, and only</div><div>switch to an unconditional =
cast, if the restrictive move is not appropriate...</div><div><br></div><di=
v><br></div><div>> A generic function working with both const and non-co=
nst sequences can indiscriminately move and get correct, optimal behavior i=
n both cases. (There are classes with movably mutable members, but they sho=
uld work either way and the intent is ambiguous.) My proposal N4166, (to be=
revised soon) provides new <font face=3D"Courier">std::initializer_li=
st</font> <wbr>types with non-const (movable) access, and the generic =
usage style is just to ask for <font face=3D"Courier">move</font> =
;and take what you get.<br></div><div><br>Are you referring to this example=
below from N4166?</div><div><br></div><div><div><div> template=
< typename t > // t is foo or foo &&.</div><div> =
void generic(std::initializer_list< t > seq) {</div><div>  =
; for (auto && f : seq) { // f is const or modifiable.</div>=
<div> smth(std::move(f)); // Move is defea=
ted by const.</div><div> }</div><div> }</di=
v></div><div><br></div><div><br></div><div>Well, this is interesting... :)<=
/div><div>I understand that you are relying on the implementation detail th=
at initializer_list </div><div>sequence always has either const or eff=
ectively-rvalue elements and never just lvalues</div><div>since one can't m=
ake initializer_list<T&> and pass it to 2 different objects...</d=
iv><div><br></div><div>To convince myself that this method is safe I had to=
review the declarations of</div><div>both classes and hope that these impl=
ementation details will not change...</div><div><br></div><div>Maybe the it=
erator type could be a wrapper that would return a T&& on operator*=
<br></div><div>and then the usage would be to std::forward<decltype(f)&g=
t;(f)? </div><div>Would it make more sense?</div><div><br></div><div><=
br></div><div>Thanks!<br></div><div>Max<br></div><div><br></div><br>On Satu=
rday, May 9, 2015 at 7:54:10 PM UTC-7, David Krauss wrote:<blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><div style=3D"word-wrap:break-word"><div><br></=
div><blockquote type=3D"cite"><div>On 2015=E2=80=9305=E2=80=9309, at 1:26 P=
M, Max Galkin <<a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-=
mailto=3D"FbM51bTHd1oJ" rel=3D"nofollow" onmousedown=3D"this.href=3D'javasc=
ript:';return true;" onclick=3D"this.href=3D'javascript:';return true;">mak=
sim...@gmail.com</a>> wrote:</div><br><div><div>Const rvalue references<=
/div><div>in general only have corner case applications, e.g. by STL [1].</=
div></div></blockquote><blockquote type=3D"cite"><br></blockquote><blockquo=
te type=3D"cite"><div><div>In all cases known to the author of the proposal=
, when std::move was called </div></div></blockquote><blockquote type=
=3D"cite"><div><div>with a const-qualified argument, it indicated a program=
mer's error. </div></div></blockquote><div><div><div><br></div></div><=
/div><div>A const rvalue reference will usually initialize a const lvalue r=
eference. This doesn=E2=80=99t indicate an error.</div><div><br></div><div>=
<div>The source of the performance issue you=E2=80=99re trying to detect is=
n=E2=80=99t usually at the <font face=3D"Courier">move(const_value)</f=
ont> at all, but somewhere upstream where someone forgot to <font=
face=3D"Courier">move</font> and the object got bound to a <font=
face=3D"Courier">const &</font> reference instead. If, in the tro=
ublesome context, the <font face=3D"Courier">move</font> really w=
asn=E2=80=99t forgotten but actually unsafe (and you can=E2=80=99t assume i=
t is), your proposal would take an innocuous corner case and make it intrac=
table.</div><div><br></div></div><div>A generic function working with both =
const and non-const sequences can indiscriminately move and get correct, op=
timal behavior in both cases. (There are classes with movably mutable membe=
rs, but they should work either way and the intent is ambiguous.) My propos=
al N4166, (to be revised soon) provides new <font face=3D"Courier">std=
::initializer_list</font> <wbr>types with non-const (movable) access, =
and the generic usage style is just to ask for <font face=3D"Courier">move<=
/font> and take what you get.</div><div><br></div><div>Anytime you pass an =
expression of const class type to a forwarding reference, it will generate =
a const rvalue reference. Do you propose to deprecate const prvalues in gen=
eral?</div><div><br></div><div><blockquote type=3D"cite"><div>Usually</div>=
<div><div>such an error does not lead to incorrect code, only to less effic=
ient code,</div><div>because instead of a move-aware overload a copying ove=
rload of the called </div><div>function is used.</div></div></blockquo=
te><div><div><div><br></div></div></div><div>There are several non-breaking=
solutions:</div><div><br></div><div>1. Implement your proposal in your own=
codebase. Usage experience will help if you still feel it to be worthy of =
standardization.</div><div>2. <font face=3D"Courier">static_assert</font> t=
he non-constness in specific instances of calls to <font face=3D"Couri=
er">move</font>, or when receiving rvalue references by forwarding.</div><d=
iv>3. Delete the const move constructor of the offending classes: <font fac=
e=3D"Courier">T::T(T const &&) =3D delete;</font>.</div></div></div=
></blockquote></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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_4302_106879807.1431241619335--
------=_Part_4301_1331019458.1431241619335--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sun, 10 May 2015 00:29:33 -0700 (PDT)
Raw View
------=_Part_3742_839310141.1431242973269
Content-Type: multipart/alternative;
boundary="----=_Part_3743_1612946291.1431242973269"
------=_Part_3743_1612946291.1431242973269
Content-Type: text/plain; charset=UTF-8
On Sunday, May 10, 2015 at 3:06:59 AM UTC-4, Max Galkin wrote:
>
> The question is, should the unconditional cast be the default, or should a
> more restricitve approach be preferred, and only
> switch to an unconditional cast, if the restrictive move is not
> appropriate...
>
There's a more relevant question that really ought to be answered first: is
the problem you cite significant enough to potentially break the world?
There's been a lot of code written that uses std::move. Some of it in
places where it could get a `const&`. You claim that these are "broken",
because they can do a copy instead of a move. I claim that it is
*functional* code even if it copies; we have lots of code that works this
way right now.
Why should we break their "broken" code that works just fine?
Until you can answer that, I'd say that your question here is rather moot.
std::move is what it is. Adding an alternative would be fine; changing it
takes more than your belief that it's not good as currently specified.
--
---
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/.
------=_Part_3743_1612946291.1431242973269
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>On Sunday, May 10, 2015 at 3:06:59 AM UTC-4, Max G=
alkin wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><=
div>The question is, should the unconditional cast be the default, or shoul=
d a more restricitve approach be preferred, and only</div><div>switch to an=
unconditional cast, if the restrictive move is not appropriate...</div></d=
iv></blockquote><div><br>There's a more relevant question that really ought=
to be answered first: is the problem you cite significant enough to potent=
ially break the world? There's been a lot of code written that uses std::mo=
ve. Some of it in places where it could get a `const&`. You claim that =
these are "broken", because they can do a copy instead of a move. I claim t=
hat it is <i>functional</i> code even if it copies; we have lots of code th=
at works this way right now.<br><br>Why should we break their "broken" code=
that works just fine?<br><br>Until you can answer that, I'd say that your =
question here is rather moot. std::move is what it is. Adding an alternativ=
e would be fine; changing it takes more than your belief that it's not good=
as currently specified.<br></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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_3743_1612946291.1431242973269--
------=_Part_3742_839310141.1431242973269--
.
Author: David Krauss <potswa@mac.com>
Date: Sun, 10 May 2015 18:04:01 +0800
Raw View
--Apple-Mail=_329C2E64-A17D-4FA1-98DB-1933E1418CEF
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8
> On 2015=E2=80=9305=E2=80=9310, at 3:06 PM, Max Galkin <maksim.galkin@gmai=
l.com> wrote:
>=20
> In what context is this happening, the situation you're describing?
I=E2=80=99m just inventing a situation where potential performance is lost,=
because you mentioned that such situations exist. Your examples didn=E2=80=
=99t involve loss of performance; they were all merely about failure to gai=
n performance by applying move where it=E2=80=99s not very applicable.
> 1. If you're in a non-generic method, and you're trying to move a variabl=
e declared as "const&" then what are you trying to achieve? It is just misl=
eading and has no effect.
I agree, it might be helpful to get a warning when std::move is applied to =
a local variable declared with the const keyword. But it=E2=80=99s only som=
ething for -Wextra.
> 2. If you are in a generic method using a universal reference, then you s=
hould probably be calling std::forward instead of std:move.
Unless the caller didn=E2=80=99t know the object was ready to expire. Gener=
ic methods can sometimes take the initiative to move.
> 3. If you're inside the move constructor intialization and some field is =
const, you can just initialize directly, without calling std::move() on it.
This isn=E2=80=99t an error, such a move() is harmless and it does what the=
implicit definition would do.
It=E2=80=99s an error to declare something as const because it shouldn=E2=
=80=99t change=E2=80=A6 only until it=E2=80=99s moved. Fields should be con=
st only rarely.
> Well, this is interesting... :)
> I understand that you are relying on the implementation detail that initi=
alizer_list=20
> sequence always has either const or effectively-rvalue elements and never=
just lvalues
> since one can't make initializer_list<T&> and pass it to 2 different obje=
cts=E2=80=A6
initializer_list<T>::iterator always yields lvalues; typically it=E2=80=99s=
only T const*. But it only needs to be const as long as two list objects m=
ight be sharing the sequence, which is an aliasing problem. Objects simply =
don=E2=80=99t have value category; lvalue or rvalue is only part of the way=
you observe an object.
You are allowed to move from the sequence elements whenever they are modifi=
able, because the modifiable version of initializer_list is only move-const=
ructible, like unique_ptr. If the caller passed the container by copy inste=
ad of by rvalue or move(), you wouldn=E2=80=99t get the chance to move from=
the sequence elements.
It would be a lot simpler if the corner case of copying an initializer_list=
simply didn=E2=80=99t exist. But, I have to design around the existing war=
ts.
> To convince myself that this method is safe I had to review the declarati=
ons of
> both classes and hope that these implementation details will not change=
=E2=80=A6
Safe from what?
The sequence is an array. This is fundamental to initializer_list. The deta=
ils will not change because they=E2=80=99re standardized, for better or wor=
se.
> Maybe the iterator type could be a wrapper that would return a T&& on ope=
rator*
> and then the usage would be to std::forward<decltype(f)>(f)?=20
> Would it make more sense?
No, that would be horrible. Never start a move without being obvious about =
it.
Asking for a move but not getting one: safe.
Merely mentioning some object and getting it erased: unsafe.
By the way, we do already have std::move_iterator, and it works only as lon=
g as the generic algorithm receiving it doesn=E2=80=99t need to access the =
same thing twice. Perhaps there=E2=80=99s a generally safe methodology for =
move iterators, but it hasn=E2=80=99t been discovered yet.
--=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/.
--Apple-Mail=_329C2E64-A17D-4FA1-98DB-1933E1418CEF
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8
<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dutf-8"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-mode: s=
pace; -webkit-line-break: after-white-space;" class=3D""><br class=3D""><di=
v><blockquote type=3D"cite" class=3D""><div class=3D"">On 2015=E2=80=9305=
=E2=80=9310, at 3:06 PM, Max Galkin <<a href=3D"mailto:maksim.galkin@gma=
il.com" class=3D"">maksim.galkin@gmail.com</a>> wrote:</div><br class=3D=
"Apple-interchange-newline"><div class=3D""><div dir=3D"ltr" class=3D""><di=
v class=3D"">In what context is this happening, the situation you're descri=
bing?</div></div></div></blockquote><div><br class=3D""></div><div>I=E2=80=
=99m just inventing a situation where potential performance is lost, becaus=
e you mentioned that such situations exist. Your examples didn=E2=80=99t in=
volve loss of performance; they were all merely about failure to gain perfo=
rmance by applying <font face=3D"Courier" class=3D"">move</font> where it=
=E2=80=99s not very applicable.</div><br class=3D""><blockquote type=3D"cit=
e" class=3D""><div class=3D""><div dir=3D"ltr" class=3D""><div class=3D"">1=
.. If you're in a non-generic method, and you're trying to move a variable d=
eclared as "const&" then what are you trying to achieve? It is just mis=
leading and has no effect.</div></div></div></blockquote><div><br class=3D"=
"></div><div>I agree, it might be helpful to get a warning when <font face=
=3D"Courier" class=3D"">std::move</font> is applied to a local variable dec=
lared with the <font face=3D"Courier" class=3D"">const</font> key=
word. But it=E2=80=99s only something for <font face=3D"Courier" class=3D""=
>-Wextra</font>.</div><br class=3D""><blockquote type=3D"cite" class=3D""><=
div class=3D""><div dir=3D"ltr" class=3D""><div class=3D"">2. If you are in=
a generic method using a universal reference, then you should probably be =
calling std::forward instead of std:move.</div></div></div></blockquote><di=
v><br class=3D""></div><div>Unless the caller didn=E2=80=99t know the objec=
t was ready to expire. Generic methods can sometimes take the initiative to=
move.</div><br class=3D""><blockquote type=3D"cite" class=3D""><div class=
=3D""><div dir=3D"ltr" class=3D""><div class=3D"">3. If you're inside the m=
ove constructor intialization and some field is const, you can just initial=
ize directly, without calling std::move() on it.</div></div></div></blockqu=
ote><div><br class=3D""></div><div>This isn=E2=80=99t an error, such a =
;<font face=3D"Courier" class=3D"">move()</font> is harmless and it does wh=
at the implicit definition would do.</div><div><br class=3D""></div><div>It=
=E2=80=99s an error to declare something as <font face=3D"Courier" class=3D=
"">const</font> because it shouldn=E2=80=99t change=E2=80=A6 only until it=
=E2=80=99s moved. Fields should be const only rarely.</div><br class=3D""><=
blockquote type=3D"cite" class=3D""><div dir=3D"ltr" class=3D""><div class=
=3D"">Well, this is interesting... :)</div><div class=3D""><div class=3D"">=
I understand that you are relying on the implementation detail that initial=
izer_list </div><div class=3D"">sequence always has either const or ef=
fectively-rvalue elements and never just lvalues</div><div class=3D"">since=
one can't make initializer_list<T&> and pass it to 2 different o=
bjects=E2=80=A6</div></div></div></blockquote><div><br class=3D""></div><di=
v><font face=3D"Courier" class=3D"">initializer_list<T>::iterator</fo=
nt> always yields lvalues; typically it=E2=80=99s only <font face=3D"Courie=
r" class=3D"">T const*</font>. But it only needs to be <font face=3D"Courie=
r" class=3D"">const</font> as long as two list objects might be sharing the=
sequence, which is an aliasing problem. Objects simply don=E2=80=99t =
have value category; lvalue or rvalue is only part of the way you observe a=
n object.</div><div><br class=3D""></div><div>You are allowed to move from =
the sequence elements whenever they are modifiable, because the modifiable =
version of <font face=3D"Courier" class=3D"">initializer_list</font> is onl=
y move-constructible, like <font face=3D"Courier" class=3D"">unique_ptr</fo=
nt>. If the caller passed the container by copy instead of by rvalue or&nbs=
p;<font face=3D"Courier" class=3D"">move()</font>, you wouldn=E2=80=99t get=
the chance to move from the sequence elements.</div><div><br class=3D""></=
div><div>It would be a lot simpler if the corner case of copying an <font f=
ace=3D"Courier" class=3D"">initializer_list</font> simply didn=E2=80=99t ex=
ist. But, I have to design around the existing warts.</div><br class=3D""><=
blockquote type=3D"cite" class=3D""><div class=3D""><div dir=3D"ltr" class=
=3D""><div class=3D""><div class=3D"">To convince myself that this method i=
s safe I had to review the declarations of</div><div class=3D"">both classe=
s and hope that these implementation details will not change=E2=80=A6</div>=
<div class=3D""></div></div></div></div></blockquote><div><br class=3D""></=
div><div>Safe from what?</div><div><br class=3D""></div><div>The sequence i=
s an array. This is fundamental to <font face=3D"Courier" class=3D"">initia=
lizer_list</font>. The details will not change because they=E2=80=99re stan=
dardized, for better or worse.</div><br class=3D""><blockquote type=3D"cite=
" class=3D""><div class=3D""><div dir=3D"ltr" class=3D""><div class=3D""><d=
iv class=3D"">Maybe the iterator type could be a wrapper that would return =
a T&& on operator*<br class=3D""></div><div class=3D"">and then the=
usage would be to std::forward<decltype(f)>(f)? </div><div clas=
s=3D"">Would it make more sense?</div></div></div></div></blockquote><br cl=
ass=3D""></div><div>No, that would be horrible. Never start a move without =
being obvious about it.</div><div><br class=3D""></div><div>Asking for a mo=
ve but not getting one: safe.</div><div>Merely mentioning some object and g=
etting it erased: unsafe.</div><div><br class=3D""></div><div>By the way, w=
e do already have <font face=3D"Courier" class=3D"">std::move_iterator</fon=
t>, and it works only as long as the generic algorithm receiving it doesn=
=E2=80=99t need to access the same thing twice. Perhaps there=E2=80=99s a g=
enerally safe methodology for move iterators, but it hasn=E2=80=99t been di=
scovered yet.</div></body></html>
<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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--Apple-Mail=_329C2E64-A17D-4FA1-98DB-1933E1418CEF--
.
Author: Max Galkin <maksim.galkin@gmail.com>
Date: Mon, 11 May 2015 23:23:08 -0700 (PDT)
Raw View
------=_Part_1848_1503575689.1431411788307
Content-Type: multipart/alternative;
boundary="----=_Part_1849_1156530774.1431411788307"
------=_Part_1849_1156530774.1431411788307
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Thanks, David, I think your initializer_list proposal has a true=20
counterexample, where you need an unconditional cast to rvalue ref no=20
matter whether the value is const or not. At least this seems to be the=20
simplest approach.
Question to all: what if the proposal would be to just add a new utility=20
method with a conditional cast only for non-const values? Without breaking=
=20
the std::move.
I don't know what the name would be, but maybe "std::make_movable" for the=
=20
sake of this argument.
Would this be a useful utility, or does it not make the bar for being a=20
useful proposal?
Thanks!
template <typename T> constexpr remove_reference_t<T>&&=20
make_movable(T&& t) noexcept
{
static_assert(!std::is_const<remove_reference_t<T>>::value,
"Cannot make a const-qualified argument movable.");
return std::move(t);
}
----
Max
On Sunday, May 10, 2015 at 6:38:43 AM UTC-7, David Krauss wrote:
>
>
> On 2015=E2=80=9305=E2=80=9310, at 3:06 PM, Max Galkin <maksim...@gmail.co=
m <javascript:>>=20
> wrote:
>
> In what context is this happening, the situation you're describing?
>
>
> I=E2=80=99m just inventing a situation where potential performance is los=
t,=20
> because you mentioned that such situations exist. Your examples didn=E2=
=80=99t=20
> involve loss of performance; they were all merely about failure to gain=
=20
> performance by applying move where it=E2=80=99s not very applicable.
>
> 1. If you're in a non-generic method, and you're trying to move a variabl=
e=20
> declared as "const&" then what are you trying to achieve? It is just=20
> misleading and has no effect.
>
>
> I agree, it might be helpful to get a warning when std::move is applied=
=20
> to a local variable declared with the const keyword. But it=E2=80=99s onl=
y=20
> something for -Wextra.
>
> 2. If you are in a generic method using a universal reference, then you=
=20
> should probably be calling std::forward instead of std:move.
>
>
> Unless the caller didn=E2=80=99t know the object was ready to expire. Gen=
eric=20
> methods can sometimes take the initiative to move.
>
> 3. If you're inside the move constructor intialization and some field is=
=20
> const, you can just initialize directly, without calling std::move() on i=
t.
>
>
> This isn=E2=80=99t an error, such a move() is harmless and it does what t=
he=20
> implicit definition would do.
>
> It=E2=80=99s an error to declare something as const because it shouldn=E2=
=80=99t change=E2=80=A6=20
> only until it=E2=80=99s moved. Fields should be const only rarely.
>
> Well, this is interesting... :)
> I understand that you are relying on the implementation detail that=20
> initializer_list=20
> sequence always has either const or effectively-rvalue elements and never=
=20
> just lvalues
> since one can't make initializer_list<T&> and pass it to 2 different=20
> objects=E2=80=A6
>
>
> initializer_list<T>::iterator always yields lvalues; typically it=E2=80=
=99s only T=20
> const*. But it only needs to be const as long as two list objects might=
=20
> be sharing the sequence, which is an aliasing problem. Objects simply don=
=E2=80=99t=20
> have value category; lvalue or rvalue is only part of the way you observe=
=20
> an object.
>
> You are allowed to move from the sequence elements whenever they are=20
> modifiable, because the modifiable version of initializer_list is only=20
> move-constructible, like unique_ptr. If the caller passed the container=
=20
> by copy instead of by rvalue or move(), you wouldn=E2=80=99t get the chan=
ce to=20
> move from the sequence elements.
>
> It would be a lot simpler if the corner case of copying an=20
> initializer_list simply didn=E2=80=99t exist. But, I have to design aroun=
d the=20
> existing warts.
>
> To convince myself that this method is safe I had to review the=20
> declarations of
> both classes and hope that these implementation details will not change=
=E2=80=A6
>
>
> Safe from what?
>
> The sequence is an array. This is fundamental to initializer_list. The=20
> details will not change because they=E2=80=99re standardized, for better =
or worse.
>
> Maybe the iterator type could be a wrapper that would return a T&& on=20
> operator*
> and then the usage would be to std::forward<decltype(f)>(f)?=20
> Would it make more sense?
>
>
> No, that would be horrible. Never start a move without being obvious abou=
t=20
> it.
>
> Asking for a move but not getting one: safe.
> Merely mentioning some object and getting it erased: unsafe.
>
> By the way, we do already have std::move_iterator, and it works only as=
=20
> long as the generic algorithm receiving it doesn=E2=80=99t need to access=
the same=20
> thing twice. Perhaps there=E2=80=99s a generally safe methodology for mov=
e=20
> iterators, but it hasn=E2=80=99t been discovered yet.
>
--=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/.
------=_Part_1849_1156530774.1431411788307
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Thanks, David, I think your initializer_list proposal has =
a true counterexample, where you need an unconditional cast to rvalue ref n=
o matter whether the value is const or not. At least this seems to be the s=
implest approach.<div><br></div><div><br></div><div>Question to all: what i=
f the proposal would be to just add a new utility method with a conditional=
cast only for non-const values? Without breaking the std::move.</div><div>=
I don't know what the name would be, but maybe "std::make_movable" for the =
sake of this argument.</div><div><br></div><div><div>Would this be a useful=
utility, or does it not make the bar for being a useful proposal?</div></d=
iv><div><br></div><div>Thanks!</div><div><br></div><div><br></div><div><div=
> template <typename T> constexpr remove_reference_t<T>&a=
mp;& </div><div> make_movable(T&& t) noexcept</div><=
div> {</div><div> static_assert(!std::is_const<<wbr>r=
emove_reference_t<T>>::value,</div><div> "Cann=
ot make a const-qualified argument movable.");</div><div><br></div><div>&nb=
sp; return std::move(t);</div><div> }</div></div><div><br></di=
v><div><br></div><div>----</div><div>Max</div><div><br><br>On Sunday, May 1=
0, 2015 at 6:38:43 AM UTC-7, David Krauss wrote:<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"word-wrap:break-word"><br><div><blockquote =
type=3D"cite"><div>On 2015=E2=80=9305=E2=80=9310, at 3:06 PM, Max Galkin &l=
t;<a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"qQvA_K=
iHp58J" rel=3D"nofollow" onmousedown=3D"this.href=3D'javascript:';return tr=
ue;" onclick=3D"this.href=3D'javascript:';return true;">maksim...@gmail.com=
</a>> wrote:</div><br><div><div dir=3D"ltr"><div>In what context is this=
happening, the situation you're describing?</div></div></div></blockquote>=
<div><br></div><div>I=E2=80=99m just inventing a situation where potential =
performance is lost, because you mentioned that such situations exist. Your=
examples didn=E2=80=99t involve loss of performance; they were all merely =
about failure to gain performance by applying <font face=3D"Courier">move</=
font> where it=E2=80=99s not very applicable.</div><br><blockquote type=3D"=
cite"><div><div dir=3D"ltr"><div>1. If you're in a non-generic method, and =
you're trying to move a variable declared as "const&" then what are you=
trying to achieve? It is just misleading and has no effect.</div></div></d=
iv></blockquote><div><br></div><div>I agree, it might be helpful to get a w=
arning when <font face=3D"Courier">std::move</font> is applied to a local v=
ariable declared with the <font face=3D"Courier">const</font> key=
word. But it=E2=80=99s only something for <font face=3D"Courier">-Wextra</f=
ont>.</div><br><blockquote type=3D"cite"><div><div dir=3D"ltr"><div>2. If y=
ou are in a generic method using a universal reference, then you should pro=
bably be calling std::forward instead of std:move.</div></div></div></block=
quote><div><br></div><div>Unless the caller didn=E2=80=99t know the object =
was ready to expire. Generic methods can sometimes take the initiative to m=
ove.</div><br><blockquote type=3D"cite"><div><div dir=3D"ltr"><div>3. If yo=
u're inside the move constructor intialization and some field is const, you=
can just initialize directly, without calling std::move() on it.</div></di=
v></div></blockquote><div><br></div><div>This isn=E2=80=99t an error, such =
a <font face=3D"Courier">move()</font> is harmless and it does what th=
e implicit definition would do.</div><div><br></div><div>It=E2=80=99s an er=
ror to declare something as <font face=3D"Courier">const</font> because it =
shouldn=E2=80=99t change=E2=80=A6 only until it=E2=80=99s moved. Fields sho=
uld be const only rarely.</div><br><blockquote type=3D"cite"><div dir=3D"lt=
r"><div>Well, this is interesting... :)</div><div><div>I understand that yo=
u are relying on the implementation detail that initializer_list </div=
><div>sequence always has either const or effectively-rvalue elements and n=
ever just lvalues</div><div>since one can't make initializer_list<T&=
> and pass it to 2 different objects=E2=80=A6</div></div></div></blockqu=
ote><div><br></div><div><font face=3D"Courier">initializer_list<T>::i=
terator</font> always yields lvalues; typically it=E2=80=99s only <font fac=
e=3D"Courier">T const*</font>. But it only needs to be <font face=3D"Courie=
r">const</font> as long as two list objects might be sharing the sequence, =
which is an aliasing problem. Objects simply don=E2=80=99t have value =
category; lvalue or rvalue is only part of the way you observe an object.</=
div><div><br></div><div>You are allowed to move from the sequence elements =
whenever they are modifiable, because the modifiable version of <font face=
=3D"Courier">initializer_list</font> is only move-constructible, like <font=
face=3D"Courier">unique_ptr</font>. If the caller passed the container by =
copy instead of by rvalue or <font face=3D"Courier">move()</font>, you=
wouldn=E2=80=99t get the chance to move from the sequence elements.</div><=
div><br></div><div>It would be a lot simpler if the corner case of copying =
an <font face=3D"Courier">initializer_list</font> simply didn=E2=80=99t exi=
st. But, I have to design around the existing warts.</div><br><blockquote t=
ype=3D"cite"><div><div dir=3D"ltr"><div><div>To convince myself that this m=
ethod is safe I had to review the declarations of</div><div>both classes an=
d hope that these implementation details will not change=E2=80=A6</div><div=
></div></div></div></div></blockquote><div><br></div><div>Safe from what?</=
div><div><br></div><div>The sequence is an array. This is fundamental to <f=
ont face=3D"Courier">initializer_list</font>. The details will not change b=
ecause they=E2=80=99re standardized, for better or worse.</div><br><blockqu=
ote type=3D"cite"><div><div dir=3D"ltr"><div><div>Maybe the iterator type c=
ould be a wrapper that would return a T&& on operator*<br></div><di=
v>and then the usage would be to std::forward<decltype(f)>(f)? <=
/div><div>Would it make more sense?</div></div></div></div></blockquote><br=
></div><div>No, that would be horrible. Never start a move without being ob=
vious about it.</div><div><br></div><div>Asking for a move but not getting =
one: safe.</div><div>Merely mentioning some object and getting it erased: u=
nsafe.</div><div><br></div><div>By the way, we do already have <font face=
=3D"Courier">std::move_iterator</font>, and it works only as long as the ge=
neric algorithm receiving it doesn=E2=80=99t need to access the same thing =
twice. Perhaps there=E2=80=99s a generally safe methodology for move iterat=
ors, but it hasn=E2=80=99t been discovered yet.</div></div></blockquote></d=
iv></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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_1849_1156530774.1431411788307--
------=_Part_1848_1503575689.1431411788307--
.
Author: David Krauss <potswa@mac.com>
Date: Tue, 12 May 2015 14:52:28 +0800
Raw View
--Apple-Mail=_C8C800A1-F741-48AF-8D7B-359738ADFD85
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8
> On 2015=E2=80=9305=E2=80=9312, at 2:23 PM, Max Galkin <maksim.galkin@gmai=
l.com> wrote:
>=20
> template <typename T> constexpr remove_reference_t<T>&&=20
> make_movable(T&& t) noexcept
> {
> static_assert(!std::is_const<remove_reference_t<T>>::value,
> "Cannot make a const-qualified argument movable.");
>=20
> return std::move(t);
> }
>=20
If you want to do it yourself, there=E2=80=99s a better way:
namespace carefully {
using std::move;
=20
template< typename t >
t const && move( t const & ) =3D delete;
}
const int k =3D 3;
int a =3D carefully::move( 5 ), // rvalue
b =3D carefully::move( a ), // non-const lvalue
c =3D carefully::move( k ), // const lvalue =3D> ERROR
d =3D carefully::move( std::move( k ) ); // already a const rvalue
http://coliru.stacked-crooked.com/a/dca0d93116346b43
This only stops cases where rvalue qualification is actually being added, a=
nd in other cases, it genuinely uses std::move just in case it has special =
status within the implementation or to some static analyzer, and it doesn=
=E2=80=99t incur any additional template instantiations.
--=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/.
--Apple-Mail=_C8C800A1-F741-48AF-8D7B-359738ADFD85
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8
<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dutf-8"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-mode: s=
pace; -webkit-line-break: after-white-space;" class=3D""><br class=3D""><di=
v><blockquote type=3D"cite" class=3D""><div class=3D"">On 2015=E2=80=9305=
=E2=80=9312, at 2:23 PM, Max Galkin <<a href=3D"mailto:maksim.galkin@gma=
il.com" class=3D"">maksim.galkin@gmail.com</a>> wrote:</div><br class=3D=
"Apple-interchange-newline"><div class=3D""><div dir=3D"ltr" class=3D""><di=
v class=3D""><div class=3D""> template <typename T> constexpr r=
emove_reference_t<T>&& </div><div class=3D""> make=
_movable(T&& t) noexcept</div><div class=3D""> {</div><div cl=
ass=3D""> static_assert(!std::is_const<<wbr class=3D"">remo=
ve_reference_t<T>>::value,</div><div class=3D""> &nbs=
p; "Cannot make a const-qualified argument movable.");</div><div class=3D""=
><br class=3D""></div><div class=3D""> return std::move(t);</d=
iv><div class=3D""> }</div></div><div class=3D""></div><div class=3D"=
"><br class=3D""></div></div></div></blockquote><div><br class=3D""></div><=
div>If you want to do it yourself, there=E2=80=99s a better way:</div><div>=
<br class=3D""></div><div><font face=3D"Courier" class=3D"">namespace caref=
ully {<br class=3D""> using std::move;<br class=3D""> &n=
bsp; <br class=3D""> template< typename t ><br clas=
s=3D""> t const && move( t const & ) =3D delete;<b=
r class=3D"">}<br class=3D""><br class=3D"">const int k =3D 3;<br class=3D"=
"><br class=3D"">int a =3D carefully::move( 5 ), // rvalue<br class=3D"">&n=
bsp; b =3D carefully::move( a ), // non-const lvalue<br class=3D"">&=
nbsp; c =3D carefully::move( k ), // const lvalue =3D> ERROR<br c=
lass=3D""> d =3D carefully::move( std::move( k ) ); // already=
a const rvalue<br class=3D""></font><br class=3D""></div><div><a href=3D"h=
ttp://coliru.stacked-crooked.com/a/dca0d93116346b43" class=3D"">http://coli=
ru.stacked-crooked.com/a/dca0d93116346b43</a></div></div><br class=3D""><di=
v class=3D"">This only stops cases where rvalue qualification is actually b=
eing added, and in other cases, it genuinely uses <font face=3D"Courier" cl=
ass=3D"">std::move</font> just in case it has special status within the imp=
lementation or to some static analyzer, and it doesn=E2=80=99t incur any ad=
ditional template instantiations.</div></body></html>
<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 <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--Apple-Mail=_C8C800A1-F741-48AF-8D7B-359738ADFD85--
.