Topic: Thoughts about std::forward
Author: Mingxin Wang <wmx16835vv@163.com>
Date: Tue, 25 Dec 2018 19:38:05 -0800 (PST)
Raw View
------=_Part_1437_1567527052.1545795485356
Content-Type: multipart/alternative;
boundary="----=_Part_1438_47687471.1545795485356"
------=_Part_1438_47687471.1545795485356
Content-Type: text/plain; charset="UTF-8"
*The first idea:*
`std::forward` and `std::move` are commonly used in library design,
especially in template metaprogramming libraries. Both of the two functions
support rvalue references as input. However, I could not think of a
meaningful use case that requires passing rvalue references to these
functions. *Is there a concrete reason that `std::forward` and
`std::move` should accept rvalue references?*
*The second idea:*
When designing template metaprogramming libraries, I found
`std::reference_wrapper` useful when IMPLICITLY indicating a type with a
value (maybe with qualifiers), and there are various function templates in
the standard library that use this pattern. For example, `std::make_pair`,
`std::make_typle`, `std::bind`, `std::invoke`, etc. *I think it could be a
good idea to add handy utilities for implicit type deduction*, not only for
3rd party libary vendor's convenience, but also to improve the wording of
these function templates with similar semantics in the standard.
For instance, there should be a type template alias (corresponding to
`std::decay`, let's may as well call it `extended_decay`) and a function
template to forward the parameters (corresponding to `std::forward`, let's
may as well call it `extended_forward`; rvale references are not supported
for now). The following code is an implementation for the utilities that is
currentely used in my libraries:
namespace detail {
template <class T>
struct reference_wrapper_traits {
static inline constexpr bool is_reference_wrapper = false;
using dereferenced_type = T;
};
template <class T>
struct reference_wrapper_traits<std::reference_wrapper<T>> {
static inline constexpr bool is_reference_wrapper = true;
using dereferenced_type = T&;
};
template <class T, bool W>
struct extended_forward_helper;
template <class T>
struct extended_forward_helper<T, false> {
static inline T&& apply(T& t) { return static_cast<T&&>(t); }
};
template <class T>
struct extended_forward_helper<T, true> {
static inline auto apply(T& t)
-> typename
reference_wrapper_traits<std::decay_t<T>>::dereferenced_type
{ return t.get(); }
};
} // namespace detail
// This type refers to `std::decay_t<T>`, unless application of `std::decay`
// results in `std::reference_wrapper<X>` for some type `X`, in which case
the
// deduced type is `X&`.
template <class T>
using extended_decay_t = typename detail::reference_wrapper_traits<
std::decay_t<T>>::dereferenced_type;
// This function forwards an lvalue reference to its original reference
type,
// unless `std::decay_t<T>` results in `std::reference_wrapper<X>` for some
type
// `X`, in which case it returns the result of `value.get()`.
//
// Note: In case an lvalue reference may be returned, it is necessary to
// explicitly announce the return type. Otherwise, there could be an
improper
// copy construction.
template <class T>
auto extended_forward(std::remove_reference_t<T>& value)
-> std::conditional_t<
detail::reference_wrapper_traits<std::decay_t<T>>::is_reference_wrapper,
typename detail::reference_wrapper_traits<std::decay_t<T>>
::dereferenced_type, T&&> {
return detail::extended_forward_helper<T,
detail::reference_wrapper_traits<
std::decay_t<T>>::is_reference_wrapper>::apply(value);
}
What do you think of the ideas?
Mingxin Wang
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/2ff776bd-453f-4af1-af45-a16816008a29%40isocpp.org.
------=_Part_1438_47687471.1545795485356
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div><i>The first idea:</i></div><div><br></div>`std::forw=
ard` and `std::move` are commonly used in library design, especially in tem=
plate metaprogramming libraries. Both of the two functions support rvalue r=
eferences as input. However, I could not think of a meaningful use case tha=
t requires passing rvalue references to these functions. <b>Is there a conc=
rete reason that `std::forward` and `std::move`=C2=A0should accept rvalue r=
eferences?</b><br><div><br></div><div><i>The second idea:</i></div><div><br=
></div><div>When designing template metaprogramming libraries, I found `std=
::reference_wrapper` useful when IMPLICITLY indicating a type with a value =
(maybe with qualifiers), and there are various function templates in the st=
andard library that use this pattern. For example, `std::make_pair`, `std::=
make_typle`, `std::bind`, `std::invoke`, etc. <b>I think it could be a good=
idea to add handy utilities for implicit type deduction</b>, not only for =
3rd party libary vendor's convenience, but also to improve the wording =
of these function templates with similar semantics in the standard.</div><d=
iv><br></div><div>For instance, there should be a type template alias (corr=
esponding to `std::decay`, let's may as well call it `extended_decay`) =
and a function template to forward the parameters (corresponding to `std::f=
orward`, let's may as well call it `extended_forward`; rvale references=
are not supported for now). The following code is an implementation for th=
e utilities that is currentely used in my libraries:</div><div><br></div><d=
iv><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250)=
; border-color: rgb(187, 187, 187); border-style: solid; border-width: 1px;=
word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprett=
yprint"><font color=3D"#660066"><div class=3D"subprettyprint">namespace det=
ail {</div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyp=
rint">template <class T></div><div class=3D"subprettyprint">struct re=
ference_wrapper_traits {</div><div class=3D"subprettyprint">=C2=A0 static i=
nline constexpr bool is_reference_wrapper =3D false;</div><div class=3D"sub=
prettyprint">=C2=A0 using dereferenced_type =3D T;</div><div class=3D"subpr=
ettyprint">};</div><div class=3D"subprettyprint"><br></div><div class=3D"su=
bprettyprint">template <class T></div><div class=3D"subprettyprint">s=
truct reference_wrapper_traits<std::reference_wrapper<T>> {</di=
v><div class=3D"subprettyprint">=C2=A0 static inline constexpr bool is_refe=
rence_wrapper =3D true;</div><div class=3D"subprettyprint">=C2=A0 using der=
eferenced_type =3D T&;</div><div class=3D"subprettyprint">};</div><div =
class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">template &=
lt;class T, bool W></div><div class=3D"subprettyprint">struct extended_f=
orward_helper;</div><div class=3D"subprettyprint"><br></div><div class=3D"s=
ubprettyprint">template <class T></div><div class=3D"subprettyprint">=
struct extended_forward_helper<T, false> {</div><div class=3D"subpret=
typrint">=C2=A0 static inline T&& apply(T& t) { return static_c=
ast<T&&>(t); }</div><div class=3D"subprettyprint">};</div><di=
v class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">template=
<class T></div><div class=3D"subprettyprint">struct extended_forward=
_helper<T, true> {</div><div class=3D"subprettyprint">=C2=A0 static i=
nline auto apply(T& t)</div><div class=3D"subprettyprint">=C2=A0 =C2=A0=
=C2=A0 -> typename reference_wrapper_traits<std::decay_t<T>>=
;::dereferenced_type</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=
=A0 { return t.get(); }</div><div class=3D"subprettyprint">};</div><div cla=
ss=3D"subprettyprint"><br></div><div class=3D"subprettyprint">}=C2=A0 // na=
mespace detail</div><div class=3D"subprettyprint"><br></div><div class=3D"s=
ubprettyprint">// This type refers to `std::decay_t<T>`, unless appli=
cation of `std::decay`</div><div class=3D"subprettyprint">// results in `st=
d::reference_wrapper<X>` for some type `X`, in which case the</div><d=
iv class=3D"subprettyprint">// deduced type is `X&`.</div><div class=3D=
"subprettyprint">template <class T></div><div class=3D"subprettyprint=
">using extended_decay_t =3D typename detail::reference_wrapper_traits<<=
/div><div class=3D"subprettyprint">=C2=A0 =C2=A0 std::decay_t<T>>:=
:dereferenced_type;</div><div class=3D"subprettyprint"><br></div><div class=
=3D"subprettyprint">// This function forwards an lvalue reference to its or=
iginal reference type,</div><div class=3D"subprettyprint">// unless `std::d=
ecay_t<T>` results in `std::reference_wrapper<X>` for some type=
</div><div class=3D"subprettyprint">// `X`, in which case it returns the re=
sult of `value.get()`.</div><div class=3D"subprettyprint">//</div><div clas=
s=3D"subprettyprint">// Note: In case an lvalue reference may be returned, =
it is necessary to</div><div class=3D"subprettyprint">// explicitly announc=
e the return type. Otherwise, there could be an improper</div><div class=3D=
"subprettyprint">// copy construction.</div><div class=3D"subprettyprint">t=
emplate <class T></div><div class=3D"subprettyprint">auto extended_fo=
rward(std::remove_reference_t<T>& value)</div><div class=3D"subpr=
ettyprint">=C2=A0 =C2=A0 -> std::conditional_t<</div><div class=3D"su=
bprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 detail::reference_wrapper_traits&=
lt;std::decay_t<T>>::is_reference_wrapper,</div><div class=3D"subp=
rettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 typename detail::reference_wrapper_=
traits<std::decay_t<T>></div><div class=3D"subprettyprint">=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 ::dereferenced_type, T&&> {</div><div c=
lass=3D"subprettyprint">=C2=A0 return detail::extended_forward_helper<T,=
detail::reference_wrapper_traits<</div><div class=3D"subprettyprint">=
=C2=A0 =C2=A0 =C2=A0 std::decay_t<T>>::is_reference_wrapper>::a=
pply(value);</div><div class=3D"subprettyprint">}</div></font></div></code>=
</div><br>What do you think of the ideas?</div><div><br></div><div>Mingxin =
Wang</div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/2ff776bd-453f-4af1-af45-a16816008a29%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/2ff776bd-453f-4af1-af45-a16816008a29=
%40isocpp.org</a>.<br />
------=_Part_1438_47687471.1545795485356--
------=_Part_1437_1567527052.1545795485356--
.
Author: Balog Pal <pasa@lib.hu>
Date: Wed, 26 Dec 2018 16:29:21 -0800 (PST)
Raw View
------=_Part_1523_1252601700.1545870561428
Content-Type: multipart/alternative;
boundary="----=_Part_1524_990635506.1545870561428"
------=_Part_1524_990635506.1545870561428
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
2018. december 26., szerda 4:38:05 UTC+1 id=C5=91pontban Mingxin Wang a=20
k=C3=B6vetkez=C5=91t =C3=ADrta:
>
> *The first idea:*
>
> `std::forward` and `std::move` are commonly used in library design,=20
> especially in template metaprogramming libraries. Both of the two functio=
ns=20
> support rvalue references as input. However, I could not think of a=20
> meaningful use case that requires passing rvalue references to these=20
> functions. *Is there a concrete reason that `std::forward` and=20
> `std::move` should accept rvalue references?*
>
>
Err, if your function has an argument of type rvalue ref and you want to=20
move or forward that?
void foo(T && i) {}
void bar(T && i) { foo(i); } // error:*: *
*no matching function for call to 'foo' *
candidate function not viable: no known conversion from 'T' to 'T &&' for=
=20
1st argument
--=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.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/36d7fdc4-c18f-455f-8af9-32c08d3be131%40isocpp.or=
g.
------=_Part_1524_990635506.1545870561428
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>2018. december 26., szerda 4:38:05 UTC+1 id=C5=91p=
ontban Mingxin Wang a k=C3=B6vetkez=C5=91t =C3=ADrta:<blockquote class=3D"g=
mail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc sol=
id;padding-left: 1ex;"><div dir=3D"ltr"><div><i>The first idea:</i></div><d=
iv><br></div>`std::forward` and `std::move` are commonly used in library de=
sign, especially in template metaprogramming libraries. Both of the two fun=
ctions support rvalue references as input. However, I could not think of a =
meaningful use case that requires passing rvalue references to these functi=
ons. <b>Is there a concrete reason that `std::forward` and `std::move`=C2=
=A0should accept rvalue references?</b><br><div><br></div></div></blockquot=
e><div><br></div><div>Err, if your function has an argument of type rvalue =
ref and you want to move or forward that?</div><div><br></div><div><div sty=
le=3D"color: #000000;background-color: #fffffe;font-family: Consolas, "><di=
v><span style=3D"color: #0000ff;">void</span><span style=3D"color: #000000;=
"> foo(T </span><span style=3D"color: #000000;">&& i) {}</span></di=
v><div><span style=3D"color: #0000ff;">void</span><span style=3D"color: #00=
0000;"> bar(</span><span style=3D"color: #0000ff;">T</span><span style=3D"c=
olor: #000000;"> && i) { foo(i); } // error:</span><a><b><span styl=
e=3D"color:#A00">: </span></b><b>no matching function for call to 'foo&=
#39; <br></b></a><p><a><b><span style=3D"color:#000"></span></b>candidate f=
unction not viable: no known conversion from 'T' to 'T &&am=
p;' for 1st argument</a></p><p><br></p><p><br></p><p><br></p><span styl=
e=3D"color: #000000;"></span></div></div></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/36d7fdc4-c18f-455f-8af9-32c08d3be131%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/36d7fdc4-c18f-455f-8af9-32c08d3be131=
%40isocpp.org</a>.<br />
------=_Part_1524_990635506.1545870561428--
------=_Part_1523_1252601700.1545870561428--
.
Author: Mingxin Wang <wmx16835vv@163.com>
Date: Wed, 26 Dec 2018 22:33:34 -0800 (PST)
Raw View
------=_Part_1782_2134442796.1545892414804
Content-Type: multipart/alternative;
boundary="----=_Part_1783_2123305595.1545892414804"
------=_Part_1783_2123305595.1545892414804
Content-Type: text/plain; charset="UTF-8"
There are two groups of overloads of `std::forward` in the standard:
*Overloads **(1)*
*template<class T>*
*constexpr T&& forward(remove_reference_t<T>& t) noexcept;*
*Overloads **(2)*
*template<class T>*
*constexpr T&& forward(remove_reference_t<T>&& t) noexcept;*
*The first idea* was about the motivation to have *overloads (2)*.
In the provided case, we should call `foo(std::forward<T>(i))` instead of
`foo(i)`. The call to `std::forward<T>(i)` is an instantiation of *overloads
(1)*, rather than *overloads (2)*.
On Thursday, December 27, 2018 at 8:29:21 AM UTC+8, Balog Pal wrote:
>
>
> Err, if your function has an argument of type rvalue ref and you want to
> move or forward that?
>
> void foo(T && i) {}
> void bar(T && i) { foo(i); } // error:*: *
> *no matching function for call to 'foo' *
>
> candidate function not viable: no known conversion from 'T' to 'T &&' for
> 1st argument
>
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/2420a3df-f851-4f61-8845-563bcc8b7983%40isocpp.org.
------=_Part_1783_2123305595.1545892414804
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>There are two groups of overloads of `std::forward` i=
n the standard:</div><div><br></div><div><b>Overloads=C2=A0</b><b>(1)</b></=
div><div><div><b>template<class T></b></div><div><b>constexpr T&&=
amp; forward(remove_reference_t<T>& t) noexcept;</b></div><div><b=
><br></b></div><div><b>Overloads=C2=A0</b><b>(2)</b></div><div><b>template&=
lt;class T></b></div><div><b>constexpr T&& forward(remove_refere=
nce_t<T>&& t) noexcept;</b></div></div><div><br></div><div><i=
>The first idea</i> was about the motivation to have <b>overloads (2)</b>.<=
/div><div><br></div><div>In the provided case, we should call `foo(std::for=
ward<T>(i))` instead of `foo(i)`. The call to `std::forward<T>(=
i)` is an instantiation of <b>overloads (1)</b>, rather than=C2=A0<b>overlo=
ads (2)</b>.</div><br>On Thursday, December 27, 2018 at 8:29:21 AM UTC+8, B=
alog Pal wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-=
left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr=
"><div><br></div><div>Err, if your function has an argument of type rvalue =
ref and you want to move or forward that?</div><div><br></div><div><div><di=
v><span style=3D"color:#0000ff">void</span><span style=3D"color:#000000"> f=
oo(T </span><span style=3D"color:#000000">&& i) {}</span></div><div=
><span style=3D"color:#0000ff">void</span><span style=3D"color:#000000"> ba=
r(</span><span style=3D"color:#0000ff">T</span><span style=3D"color:#000000=
"> && i) { foo(i); } // error:</span><a><b><span style=3D"color:#a0=
0">: </span></b><b>no matching function for call to 'foo' <br></b><=
/a><p><a><b><span style=3D"color:#000"></span></b>candidate function not vi=
able: no known conversion from 'T' to 'T &&' for 1s=
t argument</a></p><span style=3D"color:#000000"></span></div></div></div></=
div></blockquote></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/2420a3df-f851-4f61-8845-563bcc8b7983%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/2420a3df-f851-4f61-8845-563bcc8b7983=
%40isocpp.org</a>.<br />
------=_Part_1783_2123305595.1545892414804--
------=_Part_1782_2134442796.1545892414804--
.
Author: Andrey Davydov <andrey.a.davydov@gmail.com>
Date: Wed, 26 Dec 2018 23:21:04 -0800 (PST)
Raw View
------=_Part_1790_1567213631.1545895264258
Content-Type: multipart/alternative;
boundary="----=_Part_1791_1401154881.1545895264259"
------=_Part_1791_1401154881.1545895264259
Content-Type: text/plain; charset="UTF-8"
>
> There are two groups of overloads of `std::forward` in the standard:
>
> *Overloads **(1)*
> *template<class T>*
> *constexpr T&& forward(remove_reference_t<T>& t) noexcept;*
>
> *Overloads **(2)*
> *template<class T>*
> *constexpr T&& forward(remove_reference_t<T>&& t) noexcept;*
>
> *The first idea* was about the motivation to have *overloads (2)*.
>
> In the provided case, we should call `foo(std::forward<T>(i))` instead of
> `foo(i)`. The call to `std::forward<T>(i)` is an instantiation of *overloads
> (1)*, rather than *overloads (2)*.
>
template<typename T>
void foo(T &&);
template<typename T, template<typename> class Container, class Key>
void bar(Container<T> & c, Key key)
{
foo<T>(std::forward<T>(c[key]));
}
void test() {
std::vector<int> vi;
bar(vi, 0); // uses overload #1 of std::forward
std::vector<bool> vb;
bar(vb, 0); // uses overload #2 of std::forward
}
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/03eed104-3ac7-4229-88fe-64c756b35c4d%40isocpp.org.
------=_Part_1791_1401154881.1545895264259
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bor=
der-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div>There ar=
e two groups of overloads of `std::forward` in the standard:</div><div><br>=
</div><div><b>Overloads=C2=A0</b><b>(1)</b></div><div><div><b>template<c=
lass T></b></div><div><b>constexpr T&& forward(remove_reference_=
t<T>& t) noexcept;</b></div><div><b><br></b></div><div><b>Overloa=
ds=C2=A0</b><b>(2)</b></div><div><b>template<class T></b></div><div><=
b>constexpr T&& forward(remove_reference_t<T>&<wbr>& =
t) noexcept;</b></div></div><div><br></div><div><i>The first idea</i> was a=
bout the motivation to have <b>overloads (2)</b>.</div><div><br></div><div>=
In the provided case, we should call `foo(std::forward<T>(i))` instea=
d of `foo(i)`. The call to `std::forward<T>(i)` is an instantiation o=
f <b>overloads (1)</b>, rather than=C2=A0<b>overloads (2)</b>.</div></div><=
/blockquote><div><div style=3D"color: #000000;background-color: #fffffe;fon=
t-family: Consolas, " liberation=3D"" mono",=3D"" courier,=3D"" monospace;f=
ont-weight:=3D"" normal;font-size:=3D"" 14px;line-height:=3D"" 19px;white-s=
pace:=3D"" pre;"=3D""><div><span style=3D"color: #0000ff;">template</span>&=
lt;<span style=3D"color: #0000ff;">typename</span> T></div><div><span st=
yle=3D"color: #0000ff;">void</span> foo(T &&);</div><br><div><span =
style=3D"color: #0000ff;">template</span><<span style=3D"color: #0000ff;=
">typename</span> T, <span style=3D"color: #0000ff;">template</span><<sp=
an style=3D"color: #0000ff;">typename</span>> <span style=3D"color: #000=
0ff;">class</span> Container, <span style=3D"color: #0000ff;">class</span> =
Key></div><div><span style=3D"color: #0000ff;">void</span> bar(Container=
<T> & c, Key key)</div><div>{</div><div> =C2=A0 =C2=A0foo<T>=
;(std::forward<T>(c[key]));</div><div>}</div><br><div><span style=3D"=
color: #0000ff;">void</span> test() {</div><div> =C2=A0 =C2=A0std::vector&l=
t;<span style=3D"color: #0000ff;">int</span>> vi;</div><div> =C2=A0 =C2=
=A0bar(vi, <span style=3D"color: #09885a;">0</span>); // uses overload #1 o=
f std::forward</div><div> =C2=A0 =C2=A0std::vector<<span style=3D"color:=
#0000ff;">bool</span>> vb;</div><div> =C2=A0 =C2=A0bar(vb, <span style=
=3D"color: #09885a;">0</span>); // uses overload #2 of std::forward</div><d=
iv>}<span style=3D"background-color: white; color: rgb(34, 34, 34);">=C2=A0=
</span></div></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/03eed104-3ac7-4229-88fe-64c756b35c4d%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/03eed104-3ac7-4229-88fe-64c756b35c4d=
%40isocpp.org</a>.<br />
------=_Part_1791_1401154881.1545895264259--
------=_Part_1790_1567213631.1545895264258--
.
Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
Date: Thu, 27 Dec 2018 19:59:38 -0800 (PST)
Raw View
------=_Part_1838_742601143.1545969579065
Content-Type: multipart/alternative;
boundary="----=_Part_1839_1650388404.1545969579066"
------=_Part_1839_1650388404.1545969579066
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
On Thursday, December 27, 2018 at 2:21:04 AM UTC-5, Andrey Davydov wrote:
>
> template<typename T>
> void foo(T &&);
>
> template<typename T, template<typename> class Container, class Key>
> void bar(Container<T> & c, Key key)
> {
> foo<T>(std::forward<T>(c[key]));
> }
>
> void test() {
> std::vector<int> vi;
> bar(vi, 0); // uses overload #1 of std::forward
> std::vector<bool> vb;
> bar(vb, 0); // uses overload #2 of std::forward
> }=20
>
There's a lot of things wrong with this code:
- explicitly specifying template arguments on `foo` when they are deducible
- calling std::forward on something that is not a perfect-forwarded=20
parameter
- treating std::vector as if it were a template<typename> class when really=
=20
it is a template<typename...> class (this prevents compiling the example on=
=20
Clang or MSVC)
- using vector<bool> at all :)
The only appropriate way to use `std::forward` is in the construction `std:=
:forward<T>(t)`=20
where `t` is a perfect-forwarded function parameter of type `T&&` (and=20
where template parameter `T` was deduced).
When you misuse `std::forward`, you get weird effects. For example:
std::vector<int> vi;
bar(vi, 0); // uses overload #1 of std::forward
This calls overload #1 of std::forward, sure; but more importantly, it=20
winds up calling `foo<int>(int&&)` and thus "moving-out-of" vi[0] even=20
though `vi` was passed by lvalue reference to `bar`. In other words, your=
=20
`bar` always moves-out-of the elements of `c`, and therefore your `bar`=20
should actually be taking `c` by rvalue reference, not by lvalue reference.=
=20
You're essentially using `std::forward<T>` (with a non-deduced `T`) as a=20
verbose and confusing way to write `std::move`!
template<typename T, template<typename...> class Container, class Key>
void bar(Container<T> & c, Key key)
{
foo<T>(std::forward<T>(c[key])); // BAD: always equivalent to std::move
foo<T>(std::move(c[key])); // BETTER: use std::move if that's what you=
=20
mean
}
template<class Container, class Key>
void bar(Container&& c, const Key& key)
{
foo(std::forward<Container>(c)[key]); // LIKELY BEST: a valid example o=
f=20
perfect-forwarding
}
Mingxin is right that the rvalue overload of `std::forward` is never used=
=20
by idiomatic C++ code, and I'd go so far as to say it's never used by=20
*correct* C++ code.
However, if the implied proposal is "let's eliminate that overload," what=
=20
benefit will that bring? Mingxin, do you anticipate that compile times will=
=20
speed up thanks to one fewer overload resolution? We know that compile=20
times do speed up when we replace std::forward with static_cast=20
<https://stackoverflow.com/questions/43350719/static-casttt-faster-than-std=
forwardtt-for-compilation>,=20
but that's probably mostly thanks to eliminating the expensive function=20
template instantiation, not the overload resolution.
If you could get some numbers from a big project compiled with a hacked=20
libc++ or libstdc++, that would be pretty cool. (And if you're wrong about=
=20
the overload being unused in practice, that'd be an easy way to find out!)
HTH,
=E2=80=93Arthur
--=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.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/c2d6c52b-6c47-45ac-98af-6b818ec34dc7%40isocpp.or=
g.
------=_Part_1839_1650388404.1545969579066
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Thursday, December 27, 2018 at 2:21:04 AM UTC-5, Andrey=
Davydov wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-=
left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div><div><div>=
<span style=3D"color:#0000ff">template</span><<span style=3D"color:#0000=
ff">typename</span> T></div><div><span style=3D"color:#0000ff">void</spa=
n> foo(T &&);</div><br><div><span style=3D"color:#0000ff">template<=
/span><<span style=3D"color:#0000ff">typename</span> T, <span style=3D"c=
olor:#0000ff">template</span><<span style=3D"color:#0000ff">typename</sp=
an>> <span style=3D"color:#0000ff">class</span> Container, <span style=
=3D"color:#0000ff">class</span> Key></div><div><span style=3D"color:#000=
0ff">void</span> bar(Container<T> & c, Key key)</div><div>{</div>=
<div> =C2=A0 =C2=A0foo<T>(std::forward<T>(c[key]<wbr>));</div><=
div>}</div><br><div><span style=3D"color:#0000ff">void</span> test() {</div=
><div> =C2=A0 =C2=A0std::vector<<span style=3D"color:#0000ff">int</span>=
> vi;</div><div> =C2=A0 =C2=A0bar(vi, <span style=3D"color:#09885a">0</s=
pan>); // uses overload #1 of std::forward</div><div> =C2=A0 =C2=A0std::vec=
tor<<span style=3D"color:#0000ff">bool</span>> vb;</div><div> =C2=A0 =
=C2=A0bar(vb, <span style=3D"color:#09885a">0</span>); // uses overload #2 =
of std::forward</div><div>}<span style=3D"background-color:white;color:rgb(=
34,34,34)">=C2=A0</span></div></div></div></blockquote><div><br></div><div>=
<br></div><span style=3D"font-size: small;">There's a lot of things wro=
ng with this code:</span><br style=3D"font-family: Roboto, "Helvetica =
Neue", Helvetica, Arial, sans-serif;"><span style=3D"font-size: small;=
">- explicitly specifying template arguments on `foo` when they are deducib=
le</span><br style=3D"font-family: Roboto, "Helvetica Neue", Helv=
etica, Arial, sans-serif;"><span style=3D"font-size: small;">- calling std:=
:forward on something that is not a perfect-forwarded=C2=A0</span><br style=
=3D"font-family: Roboto, "Helvetica Neue", Helvetica, Arial, sans=
-serif;"><span style=3D"font-size: small;">parameter</span><br style=3D"fon=
t-family: Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;=
"><span style=3D"font-size: small;">- treating std::vector as if it were a =
template<typename> class when really=C2=A0</span><br style=3D"font-fa=
mily: Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;"><s=
pan style=3D"font-size: small;">it is a template<typename...> class (=
this prevents compiling the example on=C2=A0</span><br style=3D"font-family=
: Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;"><span =
style=3D"font-size: small;">Clang or MSVC)</span><br style=3D"font-family: =
Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;"><span st=
yle=3D"font-size: small;">- using vector<bool> at all :)</span><br st=
yle=3D"font-family: Roboto, "Helvetica Neue", Helvetica, Arial, s=
ans-serif;"><br style=3D"font-family: Roboto, "Helvetica Neue", H=
elvetica, Arial, sans-serif;"><span style=3D"font-size: small;">The only ap=
propriate way to use `std::forward` is in the construction=C2=A0</span><spa=
n style=3D"font-size: small;">`std::forward<T>(t)` where `t` is a per=
fect-forwarded function parameter of=C2=A0</span><span style=3D"font-size: =
small;">type `T&&` (and where template parameter `T` was deduced).<=
/span><br style=3D"font-family: Roboto, "Helvetica Neue", Helveti=
ca, Arial, sans-serif;"><br style=3D"font-family: Roboto, "Helvetica N=
eue", Helvetica, Arial, sans-serif;"><span style=3D"font-size: small;"=
>When you misuse `std::forward`, you get weird effects. For example:</span>=
<br style=3D"font-family: Roboto, "Helvetica Neue", Helvetica, Ar=
ial, sans-serif;"><br style=3D"font-family: Roboto, "Helvetica Neue&qu=
ot;, Helvetica, Arial, sans-serif;"><span style=3D"font-size: small;">=C2=
=A0 =C2=A0std::vector<int> vi;</span><br style=3D"font-family: Roboto=
, "Helvetica Neue", Helvetica, Arial, sans-serif;"><span style=3D=
"font-size: small;">=C2=A0 =C2=A0bar(vi, 0); // uses overload #1 of std::fo=
rward</span><br style=3D"font-family: Roboto, "Helvetica Neue", H=
elvetica, Arial, sans-serif;"><br style=3D"font-family: Roboto, "Helve=
tica Neue", Helvetica, Arial, sans-serif;"><span style=3D"font-size: s=
mall;">This calls overload #1 of std::forward, sure; but more importantly, =
it=C2=A0</span><br style=3D"font-family: Roboto, "Helvetica Neue"=
, Helvetica, Arial, sans-serif;"><span style=3D"font-size: small;">winds up=
calling `foo<int>(int&&)` and thus "moving-out-of"=
vi[0] even=C2=A0</span><br style=3D"font-family: Roboto, "Helvetica N=
eue", Helvetica, Arial, sans-serif;"><span style=3D"font-size: small;"=
>though `vi` was passed by lvalue reference to `bar`. In other words, your=
=C2=A0</span><br style=3D"font-family: Roboto, "Helvetica Neue", =
Helvetica, Arial, sans-serif;"><span style=3D"font-size: small;">`bar` alwa=
ys moves-out-of the elements of `c`, and therefore your `bar`=C2=A0</span><=
br style=3D"font-family: Roboto, "Helvetica Neue", Helvetica, Ari=
al, sans-serif;"><span style=3D"font-size: small;">should actually be takin=
g `c` by rvalue reference, not by lvalue reference.=C2=A0</span><br style=
=3D"font-family: Roboto, "Helvetica Neue", Helvetica, Arial, sans=
-serif;"><span style=3D"font-size: small;">You're essentially using `st=
d::forward<T>` (with a non-deduced `T`) as a=C2=A0</span><br style=3D=
"font-family: Roboto, "Helvetica Neue", Helvetica, Arial, sans-se=
rif;"><span style=3D"font-size: small;">verbose and confusing way to write =
`std::move`!</span><br style=3D"font-family: Roboto, "Helvetica Neue&q=
uot;, Helvetica, Arial, sans-serif;"><br style=3D"font-family: Roboto, &quo=
t;Helvetica Neue", Helvetica, Arial, sans-serif;"><span style=3D"font-=
size: small;">template<typename T, template<typename...> class Con=
tainer, class Key></span><br style=3D"font-family: Roboto, "Helveti=
ca Neue", Helvetica, Arial, sans-serif;"><span style=3D"font-size: sma=
ll;">void bar(Container<T> & c, Key key)</span><br style=3D"font-=
family: Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;">=
<span style=3D"font-size: small;">{</span><br style=3D"font-family: Roboto,=
"Helvetica Neue", Helvetica, Arial, sans-serif;"><span style=3D"=
font-size: small;">=C2=A0 =C2=A0foo<T>(std::forward<T>(c[key]</=
span><wbr style=3D"font-family: Roboto, "Helvetica Neue", Helveti=
ca, Arial, sans-serif;"><span style=3D"font-size: small;">));=C2=A0 // BAD:=
always equivalent to std::move</span><br style=3D"font-family: Roboto, &qu=
ot;Helvetica Neue", Helvetica, Arial, sans-serif;"><span style=3D"font=
-size: small;">=C2=A0 =C2=A0foo<T>(std::move(c[key]));=C2=A0 // BETTE=
R: use std::move if that's what you=C2=A0</span><span style=3D"font-siz=
e: small;">mean</span><br style=3D"font-family: Roboto, "Helvetica Neu=
e", Helvetica, Arial, sans-serif;"><span style=3D"font-size: small;">}=
</span><br style=3D"font-family: Roboto, "Helvetica Neue", Helvet=
ica, Arial, sans-serif;"><br style=3D"font-family: Roboto, "Helvetica =
Neue", Helvetica, Arial, sans-serif;"><span style=3D"font-size: small;=
">template<class Container, class Key></span><br style=3D"font-family=
: Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;"><span =
style=3D"font-size: small;">void bar(Container&& c, const Key& =
key)</span><br style=3D"font-family: Roboto, "Helvetica Neue", He=
lvetica, Arial, sans-serif;"><span style=3D"font-size: small;">{</span><br =
style=3D"font-family: Roboto, "Helvetica Neue", Helvetica, Arial,=
sans-serif;"><span style=3D"font-size: small;">=C2=A0 =C2=A0foo(std::forwa=
rd<Container>(</span><wbr style=3D"font-family: Roboto, "Helveti=
ca Neue", Helvetica, Arial, sans-serif;"><span style=3D"font-size: sma=
ll;">c)[key]);=C2=A0 // LIKELY BEST: a valid example=C2=A0</span><span styl=
e=3D"font-size: small;">of perfect-forwarding</span><br style=3D"font-famil=
y: Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;"><div>=
<span style=3D"font-size: small;">}</span></div><div><span style=3D"font-si=
ze: small;"><br></span></div><div><span style=3D"font-size: small;">Mingxin=
is right that the rvalue overload of `std::forward` is never used by idiom=
atic C++ code, and I'd go so far as to say it's never used by <i><b=
>correct</b></i> C++ code.</span></div><div><span style=3D"font-size: small=
;">However, if the implied proposal is "let's eliminate that overl=
oad," what benefit will that bring? Mingxin, do you anticipate that co=
mpile times will speed up thanks to one fewer overload resolution? We know =
that <a href=3D"https://stackoverflow.com/questions/43350719/static-casttt-=
faster-than-stdforwardtt-for-compilation">compile times do speed up when we=
replace std::forward with static_cast</a>, but that's probably mostly =
thanks to eliminating the expensive function template instantiation, not th=
e overload resolution.</span></div><div><span style=3D"font-size: small;">I=
f you could get some numbers from a big project compiled with a hacked libc=
++ or libstdc++, that would be pretty cool. (And if you're wrong about =
the overload being unused in practice, that'd be an easy way to find ou=
t!)</span></div><div><span style=3D"font-size: small;"><br></span></div><di=
v><span style=3D"font-size: small;">HTH,</span></div><div><span style=3D"fo=
nt-size: small;">=E2=80=93Arthur</span></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/c2d6c52b-6c47-45ac-98af-6b818ec34dc7%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/c2d6c52b-6c47-45ac-98af-6b818ec34dc7=
%40isocpp.org</a>.<br />
------=_Part_1839_1650388404.1545969579066--
------=_Part_1838_742601143.1545969579065--
.