Topic: `get_pointer` free function
Author: joseph.thomson@gmail.com
Date: Tue, 31 Jan 2017 06:26:29 -0800 (PST)
Raw View
------=_Part_7396_823001506.1485872789974
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
There is currently no uniform way to retrieve a pointer from an arbitrary p=
ointer or pointer-like object. One real example where such a feature would =
be useful is the proposed `propagate_const` wrapper, which currently requir=
es compatible class types to have a `get` member function. This is an intru=
sive requirement, that the user may not even have the capacity to meet.
I propose adding a `get_pointer` free function to mirror the `get` member f=
unctions present in many pointer-like types, much like how the `begin` and =
`end` free functions mirror the corresponding member functions present in m=
any range types. The default `get_pointer` implementation would look someth=
ing like this:
template <typename T>
auto get_pointer (T const& t) {
using element_type =3D pointer_traits<T>::element_type;
return static_cast<element_type*>(t);
}
This will work for `T*` and any pointer-like type that provides implicit or=
explicit conversion to `element_type*` (such as the proposed `observer_ptr=
`). I suggest casting be the default implementation because providing an ex=
plicit conversion operator seems like a much more natural way to allow conv=
ersion of pointer-like types to pointers than with an arbitrarily named fun=
ction like `get`. I suggest that an explicit conversion operator be added t=
o the standard library smart pointers, `unique_ptr` and `shared_ptr`. Types=
that cannot be converted to `element_type*` can provide a `get_pointer` fr=
ee function within the same namespace that can be found via ADL.
Thoughts?
Joseph
p.s. Sorry about the formatting of this post. I'm editing it using my phone=
, and it seems to have ended up all monospaced for some reason.
--=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/b58a5e0a-6a2a-490a-93e6-28e5cb7bf89a%40isocpp.or=
g.
------=_Part_7396_823001506.1485872789974--
.
Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
Date: Tue, 31 Jan 2017 16:23:32 -0800 (PST)
Raw View
------=_Part_7819_578234330.1485908612654
Content-Type: multipart/alternative;
boundary="----=_Part_7820_1160662008.1485908612654"
------=_Part_7820_1160662008.1485908612654
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Tuesday, January 31, 2017 at 6:26:30 AM UTC-8, joseph....@gmail.com=20
wrote:
>
> There is currently no uniform way to retrieve a pointer from an arbitrary=
=20
> pointer or pointer-like object. One real example where such a feature wou=
ld=20
> be useful is the proposed `propagate_const` wrapper, which currently=20
> requires compatible class types to have a `get` member function. This is =
an=20
> intrusive requirement, that the user may not even have the capacity to me=
et.
http://en.cppreference.com/w/cpp/experimental/propagate_const/get
I agree that the current text there seems stupid. It currently says that=20
the return value of t.get() ought to be:
> If T is an object pointer type, then t_. Otherwise, t_.get().
IMO it would be a strict usability improvement to say simply that t.get()=
=20
returns
> std::addressof(*t_).
Besides being shorter, simpler, and "obviously correct" for non-class=20
types, this would elegantly avoid the current problem for class types when=
=20
decltype(t_.get()) is not convertible to element_type.
IMHO, free functions such as your proposed get_pointer() are superior to=20
poorly defined member functions such as the currently proposed=20
propagate_const::get(), because free functions can be "overridden" using=20
ADL. But even better than a free function would be to give the member=20
function a good definition right from the get-go, so that nobody would ever=
=20
*want* to "override" it.
=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/7ad3256b-757d-4850-97ef-c7c14e3306be%40isocpp.or=
g.
------=_Part_7820_1160662008.1485908612654
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Tuesday, January 31, 2017 at 6:26:30 AM UTC-8, joseph..=
...@gmail.com wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;mar=
gin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">There is cu=
rrently no uniform way to retrieve a pointer from an arbitrary pointer or p=
ointer-like object. One real example where such a feature would be useful i=
s the proposed `propagate_const` wrapper, which currently requires compatib=
le class types to have a `get` member function. This is an intrusive requir=
ement, that the user may not even have the capacity to meet.</blockquote><d=
iv><br></div><div><a href=3D"http://en.cppreference.com/w/cpp/experimental/=
propagate_const/get">http://en.cppreference.com/w/cpp/experimental/propagat=
e_const/get</a><br></div><div><br></div><div>I agree that the current text =
there seems stupid. It currently says that the return value of t.get() ough=
t to be:</div><div>>=C2=A0<span style=3D"color: rgb(0, 0, 0); font-famil=
y: DejaVuSans, 'DejaVu Sans', arial, sans-serif;">If=C2=A0</span><c=
ode style=3D"background-color: transparent; color: rgb(0, 0, 0); font-famil=
y: DejaVuSansMono, 'DejaVu Sans Mono', courier, monospace !importan=
t;">T</code><span style=3D"color: rgb(0, 0, 0); font-family: DejaVuSans, &#=
39;DejaVu Sans', arial, sans-serif;">=C2=A0is an object pointer type, t=
hen=C2=A0</span><span class=3D"t-c" style=3D"background-color: rgba(0, 0, 0=
, 0.027451); border: 1px solid rgb(214, 214, 214); border-top-left-radius: =
3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-=
bottom-left-radius: 3px; margin-right: 2px; margin-left: 2px; padding-right=
: 2px; padding-left: 2px; display: inline-block; color: rgb(0, 0, 0); font-=
family: DejaVuSans, 'DejaVu Sans', arial, sans-serif;"><span class=
=3D"mw-geshi cpp source-cpp" style=3D"font-family: DejaVuSansMono, 'Dej=
aVu Sans Mono', courier, monospace !important; line-height: normal; whi=
te-space: nowrap;">t_</span></span><span style=3D"color: rgb(0, 0, 0); font=
-family: DejaVuSans, 'DejaVu Sans', arial, sans-serif;">. Otherwise=
,=C2=A0</span><span class=3D"t-c" style=3D"background-color: rgba(0, 0, 0, =
0.027451); border: 1px solid rgb(214, 214, 214); border-top-left-radius: 3p=
x; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bo=
ttom-left-radius: 3px; margin-right: 2px; margin-left: 2px; padding-right: =
2px; padding-left: 2px; display: inline-block; color: rgb(0, 0, 0); font-fa=
mily: DejaVuSans, 'DejaVu Sans', arial, sans-serif;"><span class=3D=
"mw-geshi cpp source-cpp" style=3D"font-family: DejaVuSansMono, 'DejaVu=
Sans Mono', courier, monospace !important; line-height: normal; white-=
space: nowrap;">t_.<span class=3D"me1">get</span><span class=3D"br0" style=
=3D"color: rgb(0, 128, 0);">(</span><span class=3D"br0" style=3D"color: rgb=
(0, 128, 0);">)</span></span></span><span style=3D"color: rgb(0, 0, 0); fon=
t-family: DejaVuSans, 'DejaVu Sans', arial, sans-serif;">.</span><b=
r></div><div>IMO it would be a strict usability improvement to say simply t=
hat t.get() returns</div><div>> <span class=3D"t-c" style=3D"margin-righ=
t: 2px; margin-left: 2px; padding-right: 2px; padding-left: 2px; border: 1p=
x solid rgb(214, 214, 214); background-color: rgba(0, 0, 0, 0.027451); bord=
er-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-=
radius: 3px; border-bottom-left-radius: 3px; display: inline-block; color: =
rgb(0, 0, 0); font-family: DejaVuSans, 'DejaVu Sans', arial, sans-s=
erif;"><span class=3D"mw-geshi cpp source-cpp" style=3D"line-height: normal=
; white-space: nowrap; font-family: DejaVuSansMono, 'DejaVu Sans Mono&#=
39;, courier, monospace !important;">std::addressof(*t_)</span></span><span=
style=3D"color: rgb(0, 0, 0); font-family: DejaVuSans, 'DejaVu Sans=
9;, arial, sans-serif;">.</span></div><div><span style=3D"color: rgb(0, 0, =
0); font-family: DejaVuSans, 'DejaVu Sans', arial, sans-serif;"><br=
></span></div><div><span style=3D"color: rgb(0, 0, 0); font-family: DejaVuS=
ans, 'DejaVu Sans', arial, sans-serif;">Besides being shorter, simp=
ler, and "obviously correct" for non-class types, this would eleg=
antly avoid the current problem for class types when </span><span style=3D"=
color: rgb(0, 0, 0);"><font face=3D"courier new, monospace">decltype(t_.get=
())</font></span><span style=3D"color: rgb(0, 0, 0); font-family: DejaVuSan=
s, 'DejaVu Sans', arial, sans-serif;"> is not convertible to=C2=A0<=
/span><span style=3D"color: rgb(0, 0, 0);"><font face=3D"courier new, monos=
pace">element_type</font></span><span style=3D"color: rgb(0, 0, 0); font-fa=
mily: DejaVuSans, 'DejaVu Sans', arial, sans-serif;">.</span></div>=
<div><br></div><div><font color=3D"#000000" face=3D"DejaVuSans, DejaVu Sans=
, arial, sans-serif">IMHO, free functions such as your proposed get_pointer=
() are superior to poorly defined member functions such as the currently pr=
oposed propagate_const::get(), because free functions can be "overridd=
en" using ADL. But even better than a free function would be to give t=
he member function a good definition right from the get-go, so that nobody =
would ever <i>want</i> to "override" it.</font></div><div><font c=
olor=3D"#000000" face=3D"DejaVuSans, DejaVu Sans, arial, sans-serif"><br></=
font></div><div><span style=3D"color: rgb(0, 0, 0); font-family: DejaVuSans=
, 'DejaVu Sans', arial, sans-serif;">=E2=80=93Arthur</span><br></di=
v><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;"><p></p><p></p><p></p><p></p>=
<p></p></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/7ad3256b-757d-4850-97ef-c7c14e3306be%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/7ad3256b-757d-4850-97ef-c7c14e3306be=
%40isocpp.org</a>.<br />
------=_Part_7820_1160662008.1485908612654--
------=_Part_7819_578234330.1485908612654--
.
Author: joseph.thomson@gmail.com
Date: Tue, 31 Jan 2017 20:52:20 -0800 (PST)
Raw View
------=_Part_4784_1041103667.1485924741021
Content-Type: multipart/alternative;
boundary="----=_Part_4785_417803497.1485924741021"
------=_Part_4785_417803497.1485924741021
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Wednesday, 1 February 2017 08:23:32 UTC+8, Arthur O'Dwyer wrote:
>
> On Tuesday, January 31, 2017 at 6:26:30 AM UTC-8, joseph....@gmail.com=20
> wrote:
>>
>> There is currently no uniform way to retrieve a pointer from an arbitrar=
y=20
>> pointer or pointer-like object. One real example where such a feature wo=
uld=20
>> be useful is the proposed `propagate_const` wrapper, which currently=20
>> requires compatible class types to have a `get` member function. This is=
an=20
>> intrusive requirement, that the user may not even have the capacity to m=
eet.
>
>
> http://en.cppreference.com/w/cpp/experimental/propagate_const/get
>
> I agree that the current text there seems stupid. It currently says that=
=20
> the return value of t.get() ought to be:
> > If T is an object pointer type, then t_. Otherwise, t_.get().
> IMO it would be a strict usability improvement to say simply that t.get()=
=20
> returns
> > std::addressof(*t_).
>
> Besides being shorter, simpler, and "obviously correct" for non-class=20
> types, this would elegantly avoid the current problem for class types whe=
n=20
> decltype(t_.get()) is not convertible to element_type.
>
=20
That wouldn't work for null pointers. Besides, I was only using=20
`propagate_const` as an example of where `get_pointer` would be useful; it=
=20
would use `get_pointer` instead of requiring compatible classes to have a=
=20
`get` member function that returns a pointer.
IMHO, free functions such as your proposed get_pointer() are superior to=20
> poorly defined member functions such as the currently proposed=20
> propagate_const::get(), because free functions can be "overridden" using=
=20
> ADL. But even better than a free function would be to give the member=20
> function a good definition right from the get-go, so that nobody would ev=
er=20
> *want* to "override" it.
>
> =E2=80=93Arthur
>
I think you are missing the point. The entire point of `get_pointer` is=20
that it can be used with any pointer or pointer-like type, facilitating=20
generic programming. I suggested that the default way of turning a=20
pointer-like type into a pointer should be via explicit conversion=20
operator, but a `get_pointer` overload can be provided using ADL if a=20
particular type does not support such a conversion.
Joseph
--=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/fe9294bf-e62f-443b-8edd-29502c8c1eda%40isocpp.or=
g.
------=_Part_4785_417803497.1485924741021
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Wednesday, 1 February 2017 08:23:32 UTC+8, Arthur O'=
;Dwyer wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-l=
eft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"=
>On Tuesday, January 31, 2017 at 6:26:30 AM UTC-8, <a>joseph....@gmail.com<=
/a> wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0=
..8ex;border-left:1px #ccc solid;padding-left:1ex">There is currently no uni=
form way to retrieve a pointer from an arbitrary pointer or pointer-like ob=
ject. One real example where such a feature would be useful is the proposed=
`propagate_const` wrapper, which currently requires compatible class types=
to have a `get` member function. This is an intrusive requirement, that th=
e user may not even have the capacity to meet.</blockquote><div><br></div><=
div><a href=3D"http://en.cppreference.com/w/cpp/experimental/propagate_cons=
t/get" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D'h=
ttp://www.google.com/url?q\x3dhttp%3A%2F%2Fen.cppreference.com%2Fw%2Fcpp%2F=
experimental%2Fpropagate_const%2Fget\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQj=
CNHDAhnZ-kDkRbZb40zbRpfPKe6qoA';return true;" onclick=3D"this.href=3D&#=
39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fen.cppreference.com%2Fw%2Fcp=
p%2Fexperimental%2Fpropagate_const%2Fget\x26sa\x3dD\x26sntz\x3d1\x26usg\x3d=
AFQjCNHDAhnZ-kDkRbZb40zbRpfPKe6qoA';return true;">http://en.cppreferenc=
e.com/w/<wbr>cpp/experimental/propagate_<wbr>const/get</a><br></div><div><b=
r></div><div>I agree that the current text there seems stupid. It currently=
says that the return value of t.get() ought to be:</div><div>>=C2=A0<sp=
an style=3D"color:rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sans',a=
rial,sans-serif">If=C2=A0</span><code style=3D"background-color:transparent=
;color:rgb(0,0,0);font-family:DejaVuSansMono,'DejaVu Sans Mono',cou=
rier,monospace!important">T</code><span style=3D"color:rgb(0,0,0);font-fami=
ly:DejaVuSans,'DejaVu Sans',arial,sans-serif">=C2=A0is an object po=
inter type, then=C2=A0</span><span style=3D"background-color:rgba(0,0,0,0.0=
27451);border:1px solid rgb(214,214,214);border-top-left-radius:3px;border-=
top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radi=
us:3px;margin-right:2px;margin-left:2px;padding-right:2px;padding-left:2px;=
display:inline-block;color:rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sa=
ns',arial,sans-serif"><span style=3D"font-family:DejaVuSansMono,'De=
jaVu Sans Mono',courier,monospace!important;line-height:normal;white-sp=
ace:nowrap">t_</span></span><span style=3D"color:rgb(0,0,0);font-family:Dej=
aVuSans,'DejaVu Sans',arial,sans-serif">. Otherwise,=C2=A0</span><s=
pan style=3D"background-color:rgba(0,0,0,0.027451);border:1px solid rgb(214=
,214,214);border-top-left-radius:3px;border-top-right-radius:3px;border-bot=
tom-right-radius:3px;border-bottom-left-radius:3px;margin-right:2px;margin-=
left:2px;padding-right:2px;padding-left:2px;display:inline-block;color:rgb(=
0,0,0);font-family:DejaVuSans,'DejaVu Sans',arial,sans-serif"><span=
style=3D"font-family:DejaVuSansMono,'DejaVu Sans Mono',courier,mon=
ospace!important;line-height:normal;white-space:nowrap">t_.<span>get</span>=
<span style=3D"color:rgb(0,128,0)">(</span><span style=3D"color:rgb(0,128,0=
)">)</span></span></span><span style=3D"color:rgb(0,0,0);font-family:DejaVu=
Sans,'DejaVu Sans',arial,sans-serif">.</span><br></div><div>IMO it =
would be a strict usability improvement to say simply that t.get() returns<=
/div><div>> <span style=3D"margin-right:2px;margin-left:2px;padding-righ=
t:2px;padding-left:2px;border:1px solid rgb(214,214,214);background-color:r=
gba(0,0,0,0.027451);border-top-left-radius:3px;border-top-right-radius:3px;=
border-bottom-right-radius:3px;border-bottom-left-radius:3px;display:inline=
-block;color:rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sans',arial,=
sans-serif"><span style=3D"line-height:normal;white-space:nowrap;font-famil=
y:DejaVuSansMono,'DejaVu Sans Mono',courier,monospace!important">st=
d::addressof(*t_)</span></span><span style=3D"color:rgb(0,0,0);font-family:=
DejaVuSans,'DejaVu Sans',arial,sans-serif">.</span></div><div><span=
style=3D"color:rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sans',ari=
al,sans-serif"><br></span></div><div><span style=3D"color:rgb(0,0,0);font-f=
amily:DejaVuSans,'DejaVu Sans',arial,sans-serif">Besides being shor=
ter, simpler, and "obviously correct" for non-class types, this w=
ould elegantly avoid the current problem for class types when </span><span =
style=3D"color:rgb(0,0,0)"><font face=3D"courier new, monospace">decltype(t=
_.get())</font></span><span style=3D"color:rgb(0,0,0);font-family:DejaVuSan=
s,'DejaVu Sans',arial,sans-serif"> is not convertible to=C2=A0</spa=
n><span style=3D"color:rgb(0,0,0)"><font face=3D"courier new, monospace">el=
ement_type</font></span><span style=3D"color:rgb(0,0,0);font-family:DejaVuS=
ans,'DejaVu Sans',arial,sans-serif">.</span></div></div></blockquot=
e><div>=C2=A0<br>That wouldn't work for null pointers. Besides, I was o=
nly using <span style=3D"font-family: courier new,monospace;">`propagate_co=
nst`</span> as an example of where <span style=3D"font-family: courier new,=
monospace;">`get_pointer`</span> would be useful; it would use <span style=
=3D"font-family: courier new,monospace;">`get_pointer`</span> instead of re=
quiring compatible classes to have a <span style=3D"font-family: courier ne=
w,monospace;">`get`</span> member function that returns a pointer.<br><br><=
/div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div></d=
iv><div><font color=3D"#000000" face=3D"DejaVuSans, DejaVu Sans, arial, san=
s-serif">IMHO, free functions such as your proposed get_pointer() are super=
ior to poorly defined member functions such as the currently proposed propa=
gate_const::get(), because free functions can be "overridden" usi=
ng ADL. But even better than a free function would be to give the member fu=
nction a good definition right from the get-go, so that nobody would ever <=
i>want</i> to "override" it.</font></div><div><font color=3D"#000=
000" face=3D"DejaVuSans, DejaVu Sans, arial, sans-serif"><br></font></div><=
div><span style=3D"color:rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sans=
',arial,sans-serif">=E2=80=93Arthur</span></div></div></blockquote><div=
><br>I think you are missing the point. The entire point of <span style=3D"=
font-family: courier new,monospace;">`get_pointer`</span> is that it can be=
used with any pointer or pointer-like type, facilitating generic programmi=
ng. I suggested that the default way of turning a pointer-like type into a =
pointer should be via explicit conversion operator, but a <span style=3D"fo=
nt-family: courier new,monospace;">`get_pointer`</span> overload can be pro=
vided using ADL if a particular type does not support such a conversion.<br=
><br>Joseph<br></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/fe9294bf-e62f-443b-8edd-29502c8c1eda%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/fe9294bf-e62f-443b-8edd-29502c8c1eda=
%40isocpp.org</a>.<br />
------=_Part_4785_417803497.1485924741021--
------=_Part_4784_1041103667.1485924741021--
.
Author: "Arthur O'Dwyer" <arthur.j.odwyer@gmail.com>
Date: Mon, 6 Feb 2017 12:52:41 -0800
Raw View
--001a114430960eefc10547e2d02e
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Tue, Jan 31, 2017 at 8:52 PM, <joseph.thomson@gmail.com> wrote:
> On Wednesday, 1 February 2017 08:23:32 UTC+8, Arthur O'Dwyer wrote:
>>
>> On Tuesday, January 31, 2017 at 6:26:30 AM UTC-8, joseph....@gmail.com
>> wrote:
>>>
>>> There is currently no uniform way to retrieve a pointer from an
>>> arbitrary pointer or pointer-like object. One real example where such a
>>> feature would be useful is the proposed `propagate_const` wrapper, whic=
h
>>> currently requires compatible class types to have a `get` member functi=
on.
>>> This is an intrusive requirement, that the user may not even have the
>>> capacity to meet.
>>
>>
>> http://en.cppreference.com/w/cpp/experimental/propagate_const/get
>>
>> I agree that the current text there seems stupid. It currently says that
>> the return value of t.get() ought to be:
>> > If T is an object pointer type, then t_. Otherwise, t_.get().
>> IMO it would be a strict usability improvement to say simply that t.get(=
)
>> returns
>> > std::addressof(*t_).
>>
>> Besides being shorter, simpler, and "obviously correct" for non-class
>> types, this would elegantly avoid the current problem for class types wh=
en
>> decltype(t_.get()) is not convertible to element_type.
>>
>
> That wouldn't work for null pointers.
>
Good point. To work with null pointers, I'd want
template<typename T>
auto *GETPOINTER*(T&& t) {
return t ? std::addressof(*t) : nullptr;
}
where this doesn't really need to be a library function in its own right,
but maybe it should be. (Similar to how *INVOKE* wasn't a library function
in its own right for a long time, but as of C++17 there were so many other
functions defined in terms of *INVOKE* that it metamorphosed into
std::invoke. Maybe getpointer should just skip the *GETPOINTER* phase
entirely.)
> Besides, I was only using `propagate_const` as an example of where
> `get_pointer` would be useful; it would use `get_pointer` instead of
> requiring compatible classes to have a `get` member function that returns
> a pointer.
>
Right. I'm saying (and I think you're agreeing) that proliferating a
Java-style zoo of interfaces (and especially implicit,
non-inheritance-based interfaces) in C++ would be a bad thing. I don't want
my smart-pointer types to have to implement a .get() member function in
addition to the natural operator* that they've already got, just in order
to enable some standard container or algorithm. Instead, I want the
standard containers and algorithms to work with all pointerish types the
same way, generically, without adding additional requirements that the
smart-pointer-implementor needs to know about and implement correctly.
>
> IMHO, free functions such as your proposed get_pointer() are superior to
>> poorly defined member functions such as the currently proposed
>> propagate_const::get(), because free functions can be "overridden" using
>> ADL. But even better than a free function would be to give the member
>> function a good definition right from the get-go, so that nobody would e=
ver
>> *want* to "override" it.
>>
>> =E2=80=93Arthur
>>
>
> I think you are missing the point. The entire point of `get_pointer` is
> that it can be used with any pointer or pointer-like type, facilitating
> generic programming. I suggested that the default way of turning a
> pointer-like type into a pointer should be via explicit conversion
> operator, but a `get_pointer` overload can be provided using ADL if a
> particular type does not support such a conversion.
>
I would hate to see smart-pointer-implementors have to deal with ADL
get_pointer() overloads or conversion operators, both of which are fairly
tricky beasts. The right implementation is just to use the operator* that
already exists for the smart-pointer type.
my $.02,
=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/CADvuK0K11eYHbfK0MWHP2wopw%2B%3DLpOd3mfmGcNGWDUw=
ak%3Dg_YA%40mail.gmail.com.
--001a114430960eefc10547e2d02e
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Tue, Jan 31, 2017 at 8:52 PM, <span dir=3D"ltr"><<a=
href=3D"mailto:joseph.thomson@gmail.com" target=3D"_blank">joseph.thomson@=
gmail.com</a>></span> wrote:<br><div class=3D"gmail_extra"><div class=3D=
"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;=
border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">On Wednesday,=
1 February 2017 08:23:32 UTC+8, Arthur O'Dwyer wrote:<blockquote clas=
s=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc =
solid;padding-left:1ex"><div dir=3D"ltr">On Tuesday, January 31, 2017 at 6:=
26:30 AM UTC-8, <a>joseph....@gmail.com</a> wrote:<blockquote class=3D"gmai=
l_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;pad=
ding-left:1ex">There is currently no uniform way to retrieve a pointer from=
an arbitrary pointer or pointer-like object. One real example where such a=
feature would be useful is the proposed `propagate_const` wrapper, which c=
urrently requires compatible class types to have a `get` member function. T=
his is an intrusive requirement, that the user may not even have the capaci=
ty to meet.</blockquote><div><br></div><div><a href=3D"http://en.cppreferen=
ce.com/w/cpp/experimental/propagate_const/get" rel=3D"nofollow" target=3D"_=
blank">http://en.cppreference.com/w/c<wbr>pp/experimental/propagate_cons<wb=
r>t/get</a><br></div><div><br></div><div>I agree that the current text ther=
e seems stupid. It currently says that the return value of t.get() ought to=
be:</div><div>>=C2=A0<span style=3D"color:rgb(0,0,0);font-family:DejaVu=
Sans,'DejaVu Sans',arial,sans-serif">If=C2=A0</span><code style=3D"=
background-color:transparent;color:rgb(0,0,0);font-family:DejaVuSansMono,&#=
39;DejaVu Sans Mono',courier,monospace!important">T</code><span style=
=3D"color:rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sans',arial,san=
s-serif">=C2=A0is an object pointer type, then=C2=A0</span><span style=3D"b=
ackground-color:rgba(0,0,0,0.027451);border:1px solid rgb(214,214,214);bord=
er-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radi=
us:3px;border-bottom-left-radius:3px;margin-right:2px;margin-left:2px;paddi=
ng-right:2px;padding-left:2px;display:inline-block;color:rgb(0,0,0);font-fa=
mily:DejaVuSans,'DejaVu Sans',arial,sans-serif"><span style=3D"font=
-family:DejaVuSansMono,'DejaVu Sans Mono',courier,monospace!importa=
nt;line-height:normal;white-space:nowrap">t_</span></span><span style=3D"co=
lor:rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sans',arial,sans-seri=
f">. Otherwise,=C2=A0</span><span style=3D"background-color:rgba(0,0,0,0.02=
7451);border:1px solid rgb(214,214,214);border-top-left-radius:3px;border-t=
op-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radiu=
s:3px;margin-right:2px;margin-left:2px;padding-right:2px;padding-left:2px;d=
isplay:inline-block;color:rgb(0,0,0);font-family:DejaVuSans,'DejaVu San=
s',arial,sans-serif"><span style=3D"font-family:DejaVuSansMono,'Dej=
aVu Sans Mono',courier,monospace!important;line-height:normal;white-spa=
ce:nowrap">t_.<span>get</span><span style=3D"color:rgb(0,128,0)">(</span><s=
pan style=3D"color:rgb(0,128,0)">)</span></span></span><span style=3D"color=
:rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sans',arial,sans-serif">=
..</span><br></div><div>IMO it would be a strict usability improvement to sa=
y simply that t.get() returns</div><div>> <span style=3D"margin-right:2p=
x;margin-left:2px;padding-right:2px;padding-left:2px;border:1px solid rgb(2=
14,214,214);background-color:rgba(0,0,0,0.027451);border-top-left-radius:3p=
x;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-=
left-radius:3px;display:inline-block;color:rgb(0,0,0);font-family:DejaVuSan=
s,'DejaVu Sans',arial,sans-serif"><span style=3D"line-height:normal=
;white-space:nowrap;font-family:DejaVuSansMono,'DejaVu Sans Mono',c=
ourier,monospace!important">std::addressof(*t_)</span></span><span style=3D=
"color:rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sans',arial,sans-s=
erif">.</span></div><div><span style=3D"color:rgb(0,0,0);font-family:DejaVu=
Sans,'DejaVu Sans',arial,sans-serif"><br></span></div><div><span st=
yle=3D"color:rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sans',arial,=
sans-serif">Besides being shorter, simpler, and "obviously correct&quo=
t; for non-class types, this would elegantly avoid the current problem for =
class types when </span><span style=3D"color:rgb(0,0,0)"><font face=3D"cour=
ier new, monospace">decltype(t_.get())</font></span><span style=3D"color:rg=
b(0,0,0);font-family:DejaVuSans,'DejaVu Sans',arial,sans-serif"> is=
not convertible to=C2=A0</span><span style=3D"color:rgb(0,0,0)"><font face=
=3D"courier new, monospace">element_type</font></span><span style=3D"color:=
rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sans',arial,sans-serif">.=
</span></div></div></blockquote><div>=C2=A0<br>That wouldn't work for n=
ull pointers.</div></div></blockquote><div><br></div><div>Good point. To wo=
rk with null pointers, I'd want</div><div><br></div><div><font face=3D"=
monospace, monospace">template<typename T></font></div><div><font fac=
e=3D"monospace, monospace">auto <i>GETPOINTER</i>(T&& t) {</font></=
div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 return t ? std::=
addressof(*t) : nullptr;</font></div><div><font face=3D"monospace, monospac=
e">}</font></div><div><br></div><div>where this doesn't really need to =
be a library function in its own right, but maybe it should be. (Similar to=
how <i><font face=3D"monospace, monospace">INVOKE</font></i> wasn't a =
library function in its own right for a long time, but as of C++17 there we=
re so many other functions defined in terms of <font face=3D"monospace, mon=
ospace"><i>INVOKE</i></font> that it metamorphosed into <font face=3D"monos=
pace, monospace">std::invoke</font>. Maybe getpointer should just skip the =
<font face=3D"monospace, monospace"><i>GETPOINTER</i></font> phase entirely=
..)</div><div><br></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" s=
tyle=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div=
dir=3D"ltr"><div>Besides, I was only using <span style=3D"font-family:cour=
ier new,monospace">`propagate_const`</span> as an example of where <span st=
yle=3D"font-family:courier new,monospace">`get_pointer`</span> would be use=
ful; it would use <span style=3D"font-family:courier new,monospace">`get_po=
inter`</span> instead of requiring compatible classes to have a <span style=
=3D"font-family:courier new,monospace">`get`</span> member function that re=
turns a pointer.<br></div></div></blockquote><div><br></div><div>Right. I&#=
39;m saying (and I think you're agreeing) that proliferating a Java-sty=
le zoo of interfaces (and especially implicit, non-inheritance-based interf=
aces) in C++ would be a bad thing. I don't want my smart-pointer types =
to have to implement a <font face=3D"monospace, monospace">.get()</font> me=
mber function in addition to the natural <font face=3D"monospace, monospace=
">operator*</font> that they've already got, just in order to enable so=
me standard container or algorithm. Instead, I want the standard containers=
and algorithms to work with all pointerish types the same way, generically=
, without adding additional requirements that the smart-pointer-implementor=
needs to know about and implement correctly.</div><div><br></div><div>=C2=
=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;borde=
r-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div><br></div><bl=
ockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-l=
eft:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div></div><div><font=
color=3D"#000000" face=3D"DejaVuSans, DejaVu Sans, arial, sans-serif">IMHO=
, free functions such as your proposed get_pointer() are superior to poorly=
defined member functions such as the currently proposed propagate_const::g=
et(), because free functions can be "overridden" using ADL. But e=
ven better than a free function would be to give the member function a good=
definition right from the get-go, so that nobody would ever <i>want</i> to=
"override" it.</font></div><div><font color=3D"#000000" face=3D"=
DejaVuSans, DejaVu Sans, arial, sans-serif"><br></font></div><div><span sty=
le=3D"color:rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sans',arial,s=
ans-serif">=E2=80=93Arthur</span></div></div></blockquote><div><br>I think =
you are missing the point. The entire point of <span style=3D"font-family:c=
ourier new,monospace">`get_pointer`</span> is that it can be used with any =
pointer or pointer-like type, facilitating generic programming. I suggested=
that the default way of turning a pointer-like type into a pointer should =
be via explicit conversion operator, but a <span style=3D"font-family:couri=
er new,monospace">`get_pointer`</span> overload can be provided using ADL i=
f a particular type does not support such a conversion.<br></div></div></bl=
ockquote><div><br></div><div>I would hate to see smart-pointer-implementors=
have to deal with ADL get_pointer() overloads or conversion operators, bot=
h of which are fairly tricky beasts. The right implementation is just to us=
e the <font face=3D"monospace, monospace">operator*</font> that already exi=
sts for the smart-pointer type.</div><div><br></div><div>my $.02,</div><div=
>=E2=80=93Arthur</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/CADvuK0K11eYHbfK0MWHP2wopw%2B%3DLpOd3=
mfmGcNGWDUwak%3Dg_YA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0K11e=
YHbfK0MWHP2wopw%2B%3DLpOd3mfmGcNGWDUwak%3Dg_YA%40mail.gmail.com</a>.<br />
--001a114430960eefc10547e2d02e--
.
Author: Joseph Thomson <joseph.thomson@gmail.com>
Date: Tue, 7 Feb 2017 08:03:39 +0800
Raw View
--f403045d6158fe6dab0547e57ac7
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Tue, Feb 7, 2017 at 4:52 AM, Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
wrote:
> On Tue, Jan 31, 2017 at 8:52 PM, <joseph.thomson@gmail.com> wrote:
>
>> On Wednesday, 1 February 2017 08:23:32 UTC+8, Arthur O'Dwyer wrote:
>>>
>>> On Tuesday, January 31, 2017 at 6:26:30 AM UTC-8, joseph....@gmail.com
>>> wrote:
>>>>
>>>> There is currently no uniform way to retrieve a pointer from an
>>>> arbitrary pointer or pointer-like object. One real example where such =
a
>>>> feature would be useful is the proposed `propagate_const` wrapper, whi=
ch
>>>> currently requires compatible class types to have a `get` member funct=
ion.
>>>> This is an intrusive requirement, that the user may not even have the
>>>> capacity to meet.
>>>
>>>
>>> http://en.cppreference.com/w/cpp/experimental/propagate_const/get
>>>
>>> I agree that the current text there seems stupid. It currently says tha=
t
>>> the return value of t.get() ought to be:
>>> > If T is an object pointer type, then t_. Otherwise, t_.get().
>>> IMO it would be a strict usability improvement to say simply that
>>> t.get() returns
>>> > std::addressof(*t_).
>>>
>>> Besides being shorter, simpler, and "obviously correct" for non-class
>>> types, this would elegantly avoid the current problem for class types w=
hen
>>> decltype(t_.get()) is not convertible to element_type.
>>>
>>
>> That wouldn't work for null pointers.
>>
>
> Good point. To work with null pointers, I'd want
>
> template<typename T>
> auto *GETPOINTER*(T&& t) {
> return t ? std::addressof(*t) : nullptr;
> }
>
The problem is that not all pointer-like types are contextually convertible
to `bool`.
> where this doesn't really need to be a library function in its own right,
> but maybe it should be. (Similar to how *INVOKE* wasn't a library
> function in its own right for a long time, but as of C++17 there were so
> many other functions defined in terms of *INVOKE* that it metamorphosed
> into std::invoke. Maybe getpointer should just skip the *GETPOINTER*
> phase entirely.)
>
I think `get_pointer` would be useful for non-standard libraries as well,
so I think it should be a library function.
Besides, I was only using `propagate_const` as an example of where
>> `get_pointer` would be useful; it would use `get_pointer` instead of
>> requiring compatible classes to have a `get` member function that
>> returns a pointer.
>>
>
> Right. I'm saying (and I think you're agreeing) that proliferating a
> Java-style zoo of interfaces (and especially implicit,
> non-inheritance-based interfaces) in C++ would be a bad thing. I don't wa=
nt
> my smart-pointer types to have to implement a .get() member function in
> addition to the natural operator* that they've already got, just in order
> to enable some standard container or algorithm. Instead, I want the
> standard containers and algorithms to work with all pointerish types the
> same way, generically, without adding additional requirements that the
> smart-pointer-implementor needs to know about and implement correctly.
>
Yep. As I alluded to, the problem is that pointer-like types may or may not
implement the NullablePointer
<http://en.cppreference.com/w/cpp/concept/NullablePointer> concept. Thus,
`operator*` cannot be reliably used in this way.
>> IMHO, free functions such as your proposed get_pointer() are superior to
>>> poorly defined member functions such as the currently proposed
>>> propagate_const::get(), because free functions can be "overridden" usin=
g
>>> ADL. But even better than a free function would be to give the member
>>> function a good definition right from the get-go, so that nobody would =
ever
>>> *want* to "override" it.
>>>
>>> =E2=80=93Arthur
>>>
>>
>> I think you are missing the point. The entire point of `get_pointer` is
>> that it can be used with any pointer or pointer-like type, facilitating
>> generic programming. I suggested that the default way of turning a
>> pointer-like type into a pointer should be via explicit conversion
>> operator, but a `get_pointer` overload can be provided using ADL if a
>> particular type does not support such a conversion.
>>
>
> I would hate to see smart-pointer-implementors have to deal with ADL
> get_pointer() overloads or conversion operators, both of which are fairly
> tricky beasts. The right implementation is just to use the operator* that
> already exists for the smart-pointer type.
>
Given that `operator*` cannot be used, I'm not sure there is any other way.
Also, I happened to stumble across the proposal
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4284.html> for
the concept of "contiguous iterators", an earlier version of which proposes
the addition of the `pointer_from` free function, which does essentially
the same thing as `get_pointer` but with a focus on iterators. That
proposal suggests that `pointer_from` itself uses ADL to call a
`do_pointer_from` function. This has the advantage that users of
`pointer_from` do not have to know about ADL. When I suggested using
invocation of `get_pointer` itself using ADL, I thought that a precident
had been set by `swap`, but I now realise that `swap` will work (just
perhaps less efficiently) without the caller knowing about ADL. The
proposal even mentioned that `pointer_from` could be extended to smart
pointer types. I wonder what happened to this part of the proposal.
--=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/CAHocnE_n-4XMFshXZcuvsRTXvM9CEPzhf5rcTj_5t4QQY3z=
TSg%40mail.gmail.com.
--f403045d6158fe6dab0547e57ac7
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On T=
ue, Feb 7, 2017 at 4:52 AM, Arthur O'Dwyer <span dir=3D"ltr"><<a hre=
f=3D"mailto:arthur.j.odwyer@gmail.com" target=3D"_blank">arthur.j.odwyer@gm=
ail.com</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D=
"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D=
"ltr"><span class=3D"">On Tue, Jan 31, 2017 at 8:52 PM, <span dir=3D"ltr">=
<<a href=3D"mailto:joseph.thomson@gmail.com" target=3D"_blank">joseph.th=
omson@gmail.com</a>></span> wrote:<br></span><div class=3D"gmail_extra">=
<div class=3D"gmail_quote"><span class=3D""><blockquote class=3D"gmail_quot=
e" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">=
<div dir=3D"ltr">On Wednesday, 1 February 2017 08:23:32 UTC+8, Arthur O'=
;Dwyer wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-le=
ft:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">On T=
uesday, January 31, 2017 at 6:26:30 AM UTC-8, <a>joseph....@gmail.com</a> w=
rote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;=
border-left:1px #ccc solid;padding-left:1ex">There is currently no uniform =
way to retrieve a pointer from an arbitrary pointer or pointer-like object.=
One real example where such a feature would be useful is the proposed `pro=
pagate_const` wrapper, which currently requires compatible class types to h=
ave a `get` member function. This is an intrusive requirement, that the use=
r may not even have the capacity to meet.</blockquote><div><br></div><div><=
a href=3D"http://en.cppreference.com/w/cpp/experimental/propagate_const/get=
" rel=3D"nofollow" target=3D"_blank">http://en.cppreference.com/w/c<wbr>pp/=
experimental/propagate_cons<wbr>t/get</a><br></div><div><br></div><div>I ag=
ree that the current text there seems stupid. It currently says that the re=
turn value of t.get() ought to be:</div><div>>=C2=A0<span style=3D"color=
:rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sans',arial,sans-serif">=
If=C2=A0</span><code style=3D"background-color:transparent;color:rgb(0,0,0)=
;font-family:DejaVuSansMono,'DejaVu Sans Mono',courier,monospace!im=
portant">T</code><span style=3D"color:rgb(0,0,0);font-family:DejaVuSans,=
9;DejaVu Sans',arial,sans-serif">=C2=A0is an object pointer type, then=
=C2=A0</span><span style=3D"background-color:rgba(0,0,0,0.027451);border:1p=
x solid rgb(214,214,214);border-top-left-radius:3px;border-top-right-radius=
:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;margin-ri=
ght:2px;margin-left:2px;padding-right:2px;padding-left:2px;display:inline-b=
lock;color:rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sans',arial,sa=
ns-serif"><span style=3D"font-family:DejaVuSansMono,'DejaVu Sans Mono&#=
39;,courier,monospace!important;line-height:normal;white-space:nowrap">t_</=
span></span><span style=3D"color:rgb(0,0,0);font-family:DejaVuSans,'Dej=
aVu Sans',arial,sans-serif">. Otherwise,=C2=A0</span><span style=3D"bac=
kground-color:rgba(0,0,0,0.027451);border:1px solid rgb(214,214,214);border=
-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius=
:3px;border-bottom-left-radius:3px;margin-right:2px;margin-left:2px;padding=
-right:2px;padding-left:2px;display:inline-block;color:rgb(0,0,0);font-fami=
ly:DejaVuSans,'DejaVu Sans',arial,sans-serif"><span style=3D"font-f=
amily:DejaVuSansMono,'DejaVu Sans Mono',courier,monospace!important=
;line-height:normal;white-space:nowrap">t_.<span>get</span><span style=3D"c=
olor:rgb(0,128,0)">(</span><span style=3D"color:rgb(0,128,0)">)</span></spa=
n></span><span style=3D"color:rgb(0,0,0);font-family:DejaVuSans,'DejaVu=
Sans',arial,sans-serif">.</span><br></div><div>IMO it would be a stric=
t usability improvement to say simply that t.get() returns</div><div>> <=
span style=3D"margin-right:2px;margin-left:2px;padding-right:2px;padding-le=
ft:2px;border:1px solid rgb(214,214,214);background-color:rgba(0,0,0,0.0274=
51);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-ri=
ght-radius:3px;border-bottom-left-radius:3px;display:inline-block;color:rgb=
(0,0,0);font-family:DejaVuSans,'DejaVu Sans',arial,sans-serif"><spa=
n style=3D"line-height:normal;white-space:nowrap;font-family:DejaVuSansMono=
,'DejaVu Sans Mono',courier,monospace!important">std::addressof(*t_=
)</span></span><span style=3D"color:rgb(0,0,0);font-family:DejaVuSans,'=
DejaVu Sans',arial,sans-serif">.</span></div><div><span style=3D"color:=
rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sans',arial,sans-serif"><=
br></span></div><div><span style=3D"color:rgb(0,0,0);font-family:DejaVuSans=
,'DejaVu Sans',arial,sans-serif">Besides being shorter, simpler, an=
d "obviously correct" for non-class types, this would elegantly a=
void the current problem for class types when </span><span style=3D"color:r=
gb(0,0,0)"><font face=3D"courier new, monospace">decltype(t_.get())</font><=
/span><span style=3D"color:rgb(0,0,0);font-family:DejaVuSans,'DejaVu Sa=
ns',arial,sans-serif"> is not convertible to=C2=A0</span><span style=3D=
"color:rgb(0,0,0)"><font face=3D"courier new, monospace">element_type</font=
></span><span style=3D"color:rgb(0,0,0);font-family:DejaVuSans,'DejaVu =
Sans',arial,sans-serif">.</span></div></div></blockquote><div>=C2=A0<br=
>That wouldn't work for null pointers.</div></div></blockquote><div><br=
></div></span><div>Good point. To work with null pointers, I'd want</di=
v><div><br></div><div><font face=3D"monospace, monospace">template<typen=
ame T></font></div><div><font face=3D"monospace, monospace">auto <i>GETP=
OINTER</i>(T&& t) {</font></div><div><font face=3D"monospace, monos=
pace">=C2=A0 =C2=A0 return t ? std::addressof(*t) : nullptr;</font></div><d=
iv><font face=3D"monospace, monospace">}</font></div></div></div></div></bl=
ockquote><div><br></div><div>The problem is that not all pointer-like types=
are contextually convertible to <span style=3D"font-family:monospace,monos=
pace">`bool`</span>.<br></div><div>=C2=A0</div><blockquote class=3D"gmail_q=
uote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1e=
x"><div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><=
div>where this doesn't really need to be a library function in its own =
right, but maybe it should be. (Similar to how <i><font face=3D"monospace, =
monospace">INVOKE</font></i> wasn't a library function in its own right=
for a long time, but as of C++17 there were so many other functions define=
d in terms of <font face=3D"monospace, monospace"><i>INVOKE</i></font> that=
it metamorphosed into <font face=3D"monospace, monospace">std::invoke</fon=
t>. Maybe getpointer should just skip the <font face=3D"monospace, monospac=
e"><i>GETPOINTER</i></font> phase entirely.)</div><span class=3D""></span><=
/div></div></div></blockquote><div><br></div><div>I think <span style=3D"fo=
nt-family:monospace,monospace">`get_pointer`</span> would be useful for non=
-standard libraries as well, so I think it should be a library function.<br=
></div><div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0=
0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div =
class=3D"gmail_extra"><div class=3D"gmail_quote"><span class=3D""><blockquo=
te class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc so=
lid;padding-left:1ex"><div dir=3D"ltr"><div>Besides, I was only using <span=
style=3D"font-family:courier new,monospace">`propagate_const`</span> as an=
example of where <span style=3D"font-family:courier new,monospace">`get_po=
inter`</span> would be useful; it would use <span style=3D"font-family:cour=
ier new,monospace">`get_pointer`</span> instead of requiring compatible cla=
sses to have a <span style=3D"font-family:courier new,monospace">`get`</spa=
n> member function that returns a pointer.<br></div></div></blockquote><div=
><br></div></span><div>Right. I'm saying (and I think you're agreei=
ng) that proliferating a Java-style zoo of interfaces (and especially impli=
cit, non-inheritance-based interfaces) in C++ would be a bad thing. I don&#=
39;t want my smart-pointer types to have to implement a <font face=3D"monos=
pace, monospace">.get()</font> member function in addition to the natural <=
font face=3D"monospace, monospace">operator*</font> that they've alread=
y got, just in order to enable some standard container or algorithm. Instea=
d, I want the standard containers and algorithms to work with all pointeris=
h types the same way, generically, without adding additional requirements t=
hat the smart-pointer-implementor needs to know about and implement correct=
ly.</div><span class=3D""></span></div></div></div></blockquote><div>=C2=A0=
<br></div><div>Yep. As I alluded to, the problem is that pointer-like types=
may or may not implement the <span style=3D"font-family:monospace,monospac=
e"><a href=3D"http://en.cppreference.com/w/cpp/concept/NullablePointer">Nul=
lablePointer</a></span> concept. Thus, <span style=3D"font-family:monospace=
,monospace">`operator*`<font face=3D"arial,helvetica,sans-serif"> cannot be=
reliably used in this way.</font></span><br></div><div><br></div><blockquo=
te class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc so=
lid;padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><div clas=
s=3D"gmail_quote"><span class=3D""><div></div><blockquote class=3D"gmail_qu=
ote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex=
"><div dir=3D"ltr"><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></div><div><font color=3D"#000000" face=3D"DejaVuSan=
s, DejaVu Sans, arial, sans-serif">IMHO, free functions such as your propos=
ed get_pointer() are superior to poorly defined member functions such as th=
e currently proposed propagate_const::get(), because free functions can be =
"overridden" using ADL. But even better than a free function woul=
d be to give the member function a good definition right from the get-go, s=
o that nobody would ever <i>want</i> to "override" it.</font></di=
v><div><font color=3D"#000000" face=3D"DejaVuSans, DejaVu Sans, arial, sans=
-serif"><br></font></div><div><span style=3D"color:rgb(0,0,0);font-family:D=
ejaVuSans,'DejaVu Sans',arial,sans-serif">=E2=80=93Arthur</span></d=
iv></div></blockquote><div><br>I think you are missing the point. The entir=
e point of <span style=3D"font-family:courier new,monospace">`get_pointer`<=
/span> is that it can be used with any pointer or pointer-like type, facili=
tating generic programming. I suggested that the default way of turning a p=
ointer-like type into a pointer should be via explicit conversion operator,=
but a <span style=3D"font-family:courier new,monospace">`get_pointer`</spa=
n> overload can be provided using ADL if a particular type does not support=
such a conversion.<br></div></div></blockquote><div><br></div></span><div>=
I would hate to see smart-pointer-implementors have to deal with ADL get_po=
inter() overloads or conversion operators, both of which are fairly tricky =
beasts. The right implementation is just to use the <font face=3D"monospace=
, monospace">operator*</font> that already exists for the smart-pointer typ=
e.</div></div></div></div></blockquote><div><br></div><div>Given that <span=
style=3D"font-family:monospace,monospace">`operator*`</span> cannot be use=
d, I'm not sure there is any other way.<br><br></div><div>Also, I happe=
ned to stumble across the <a href=3D"http://www.open-std.org/jtc1/sc22/wg21=
/docs/papers/2014/n4284.html">proposal</a> for the concept of "contigu=
ous iterators", an earlier version of which proposes the addition of t=
he <span style=3D"font-family:monospace,monospace">`pointer_from`</span> fr=
ee function, which does essentially the same thing as <span style=3D"font-f=
amily:monospace,monospace">`get_pointer`</span> but with a focus on iterato=
rs. That proposal suggests that <span style=3D"font-family:monospace,monosp=
ace">`pointer_from`</span> itself uses ADL to call a <span style=3D"font-fa=
mily:monospace,monospace">`do_pointer_from`</span> function. This has the a=
dvantage that users of <span style=3D"font-family:monospace,monospace">`poi=
nter_from`</span> do not have to know about ADL. When I suggested using inv=
ocation of <span style=3D"font-family:monospace,monospace">`get_pointer`</s=
pan> itself using ADL, I thought that a precident had been set by <span sty=
le=3D"font-family:monospace,monospace">`swap`</span>, but I now realise tha=
t <span style=3D"font-family:monospace,monospace">`swap`</span> will work (=
just perhaps less efficiently) without the caller knowing about ADL. The pr=
oposal even mentioned that <span style=3D"font-family:monospace,monospace">=
`pointer_from`</span> could be extended to smart pointer types. I wonder wh=
at happened to this part of the proposal.<br></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/CAHocnE_n-4XMFshXZcuvsRTXvM9CEPzhf5rc=
Tj_5t4QQY3zTSg%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">htt=
ps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHocnE_n-4XMFshX=
ZcuvsRTXvM9CEPzhf5rcTj_5t4QQY3zTSg%40mail.gmail.com</a>.<br />
--f403045d6158fe6dab0547e57ac7--
.
Author: "Arthur O'Dwyer" <arthur.j.odwyer@gmail.com>
Date: Mon, 6 Feb 2017 18:54:24 -0800
Raw View
--001a11443096a2fa9f0547e7dde9
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Mon, Feb 6, 2017 at 4:03 PM, Joseph Thomson <joseph.thomson@gmail.com>
wrote:
> On Tue, Feb 7, 2017 at 4:52 AM, Arthur O'Dwyer <arthur.j.odwyer@gmail.com=
>
> wrote:
>
>> On Tue, Jan 31, 2017 at 8:52 PM, <joseph.thomson@gmail.com> wrote:
>>
>>> On Wednesday, 1 February 2017 08:23:32 UTC+8, Arthur O'Dwyer wrote:
>>>>
>>>> On Tuesday, January 31, 2017 at 6:26:30 AM UTC-8, joseph....@gmail.com
>>>> wrote:
>>>>>
>>>>> There is currently no uniform way to retrieve a pointer from an
>>>>> arbitrary pointer or pointer-like object. One real example where such=
a
>>>>> feature would be useful is the proposed `propagate_const` wrapper, wh=
ich
>>>>> currently requires compatible class types to have a `get` member func=
tion.
>>>>> This is an intrusive requirement, that the user may not even have the
>>>>> capacity to meet.
>>>>
>>>>
>>>> http://en.cppreference.com/w/cpp/experimental/propagate_const/get
>>>>
>>>> I agree that the current text there seems stupid. It currently says
>>>> that the return value of t.get() ought to be:
>>>> > If T is an object pointer type, then t_. Otherwise, t_.get().
>>>> IMO it would be a strict usability improvement to say simply that
>>>> t.get() returns
>>>> > std::addressof(*t_).
>>>>
>>>> Besides being shorter, simpler, and "obviously correct" for non-class
>>>> types, this would elegantly avoid the current problem for class types =
when
>>>> decltype(t_.get()) is not convertible to element_type.
>>>>
>>>
>>> That wouldn't work for null pointers.
>>>
>>
>> Good point. To work with null pointers, I'd want
>>
>> template<typename T>
>> auto *GETPOINTER*(T&& t) {
>> return t ? std::addressof(*t) : nullptr;
>> }
>>
>
> The problem is that not all pointer-like types are contextually
> convertible to `bool`.
>
I'd say either that yes they are; or else that you could replace t above
with t !=3D nullptr or even t !=3D decltype(t){} without loss of sense. I d=
on't
have a particular preference among those three options.
>
>
>> where this doesn't really need to be a library function in its own right=
,
>> but maybe it should be. (Similar to how *INVOKE* wasn't a library
>> function in its own right for a long time, but as of C++17 there were so
>> many other functions defined in terms of *INVOKE* that it metamorphosed
>> into std::invoke. Maybe getpointer should just skip the *GETPOINTER*
>> phase entirely.)
>>
>
> I think `get_pointer` would be useful for non-standard libraries as well,
> so I think it should be a library function.
>
Fair. But IMO, just like *INVOKE*/std::invoke, it should have well-defined
behavior that is provided 100% by the implementation; it should not require
non-gurus to understand it, implement it, or otherwise interact with it
except to *call* it.
> Besides, I was only using `propagate_const` as an example of where
>>> `get_pointer` would be useful; it would use `get_pointer` instead of
>>> requiring compatible classes to have a `get` member function that
>>> returns a pointer.
>>>
>>
>> Right. I'm saying (and I think you're agreeing) that proliferating a
>> Java-style zoo of interfaces (and especially implicit,
>> non-inheritance-based interfaces) in C++ would be a bad thing. I don't w=
ant
>> my smart-pointer types to have to implement a .get() member function in
>> addition to the natural operator* that they've already got, just in
>> order to enable some standard container or algorithm. Instead, I want th=
e
>> standard containers and algorithms to work with all pointerish types the
>> same way, generically, without adding additional requirements that the
>> smart-pointer-implementor needs to know about and implement correctly.
>>
>
> Yep. As I alluded to, the problem is that pointer-like types may or may
> not implement the NullablePointer
> <http://en.cppreference.com/w/cpp/concept/NullablePointer> concept. Thus,
> `operator*` cannot be reliably used in this way.
>
NullablePointer <http://en.cppreference.com/w/cpp/concept/NullablePointer>
does not actually require dereferenceability =E2=80=94 which IMHO means it'=
s
horribly misnamed, but let that lie for now.
I agree that NullablePointer
<http://en.cppreference.com/w/cpp/concept/NullablePointer> doesn't model
anything remotely resembling "pointer-like". However, I claim that anything
"pointer-like" must at least conditionally support dereferencing; that's
what it means for A to "point to" B. "A points to B" means that when you
dereference A, you get B.
Now, there is still a problem, even in my happy world where all
"pointer-like" types implement operator*. The problem is that sometimes a
pointer can be non-null and *still* not point to an object. For example:
std::vector<int> a(42);
int *p =3D &a[0] + 42;
assert(p !=3D decltype(p){});
// Nevertheless we are not allowed to call std::addressof(*p) as far as
I know
auto it =3D a.end();
assert(it !=3D decltype(it){});
// Nevertheless we are not allowed to call std::addressof(*it)
What behavior would you want for std::get_pointer(p) (respectively
std::get_pointer(it)) in this case?
I suspect you'd want std::get_pointer(p) =3D=3D p somehow. I hope you're *n=
ot*
going to claim that decltype(it) is "not a pointer-like type"; but I'm not
sure it's implementable to mandate that std::get_pointer(it) consistently
return either nullptr or p.
By the way, does your intuition agree with mine that *std::exception_ptr is
not a "pointer-like type"*? (It does model NullablePointer, but it is not
dereferenceable and doesn't "point to" anything in a meaningful sense.)
Alternatively, if you think it *is* a pointer-like type, what should be
returned by std::get_pointer(std::current_exception())?
=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/CADvuK0L1TmJOQwnZYub177%3DqD13ygANeg4h_CuuJYW1Uh=
haz3Q%40mail.gmail.com.
--001a11443096a2fa9f0547e7dde9
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Mon, Feb 6, 2017 at 4:03 PM, Joseph Thomson <span dir=
=3D"ltr"><<a href=3D"mailto:joseph.thomson@gmail.com" target=3D"_blank">=
joseph.thomson@gmail.com</a>></span> wrote:<br><div class=3D"gmail_extra=
"><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"mar=
gin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,2=
04);border-left-style:solid;padding-left:1ex"><div dir=3D"ltr"><div class=
=3D"gmail_extra"><div class=3D"gmail_quote"><span class=3D"gmail-">On Tue, =
Feb 7, 2017 at 4:52 AM, Arthur O'Dwyer <span dir=3D"ltr"><<a href=3D=
"mailto:arthur.j.odwyer@gmail.com" target=3D"_blank">arthur.j.odwyer@gmail.=
com</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"mar=
gin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,2=
04);border-left-style:solid;padding-left:1ex"><div dir=3D"ltr"><span>On Tue=
, Jan 31, 2017 at 8:52 PM, <span dir=3D"ltr"><<a href=3D"mailto:joseph.=
thomson@gmail.com" target=3D"_blank">joseph.thomson@gmail.com</a>></span=
> wrote:<br></span><div class=3D"gmail_extra"><div class=3D"gmail_quote"><s=
pan><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bor=
der-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:sol=
id;padding-left:1ex"><div dir=3D"ltr">On Wednesday, 1 February 2017 08:23:3=
2 UTC+8, Arthur O'Dwyer wrote:<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">On Tu=
esday, January 31, 2017 at 6:26:30 AM UTC-8, <a>joseph....@gmail.com</a> wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bor=
der-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:sol=
id;padding-left:1ex">There is currently no uniform way to retrieve a pointe=
r from an arbitrary pointer or pointer-like object. One real example where =
such a feature would be useful is the proposed `propagate_const` wrapper, w=
hich currently requires compatible class types to have a `get` member funct=
ion. This is an intrusive requirement, that the user may not even have the =
capacity to meet.</blockquote><div><br></div><div><a href=3D"http://en.cppr=
eference.com/w/cpp/experimental/propagate_const/get" rel=3D"nofollow" targe=
t=3D"_blank">http://en.cppreference.com/w/c<wbr>pp/experimental/propagate_c=
ons<wbr>t/get</a><br></div><div><br></div><div>I agree that the current tex=
t there seems stupid. It currently says that the return value of t.get() ou=
ght to be:</div><div>>=C2=A0<span style=3D"color:rgb(0,0,0);font-family:=
dejavusans,'dejavu sans',arial,sans-serif">If=C2=A0</span><code sty=
le=3D"background-color:transparent;color:rgb(0,0,0);font-family:dejavusansm=
ono,'dejavu sans mono',courier,monospace">T</code><span style=3D"co=
lor:rgb(0,0,0);font-family:dejavusans,'dejavu sans',arial,sans-seri=
f">=C2=A0is an object pointer type, then=C2=A0</span><span style=3D"backgro=
und-color:rgba(0,0,0,0.027451);border:1px solid rgb(214,214,214);border-top=
-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px=
;border-bottom-left-radius:3px;margin-right:2px;margin-left:2px;padding-rig=
ht:2px;padding-left:2px;display:inline-block;color:rgb(0,0,0);font-family:d=
ejavusans,'dejavu sans',arial,sans-serif"><span style=3D"line-heigh=
t:normal;white-space:nowrap;font-family:dejavusansmono,'dejavu sans mon=
o',courier,monospace">t_</span></span><span style=3D"color:rgb(0,0,0);f=
ont-family:dejavusans,'dejavu sans',arial,sans-serif">. Otherwise,=
=C2=A0</span><span style=3D"background-color:rgba(0,0,0,0.027451);border:1p=
x solid rgb(214,214,214);border-top-left-radius:3px;border-top-right-radius=
:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;margin-ri=
ght:2px;margin-left:2px;padding-right:2px;padding-left:2px;display:inline-b=
lock;color:rgb(0,0,0);font-family:dejavusans,'dejavu sans',arial,sa=
ns-serif"><span style=3D"line-height:normal;white-space:nowrap;font-family:=
dejavusansmono,'dejavu sans mono',courier,monospace">t_.<span>get</=
span><span style=3D"color:rgb(0,128,0)">(</span><span style=3D"color:rgb(0,=
128,0)">)</span></span></span><span style=3D"color:rgb(0,0,0);font-family:d=
ejavusans,'dejavu sans',arial,sans-serif">.</span><br></div><div>IM=
O it would be a strict usability improvement to say simply that t.get() ret=
urns</div><div>> <span style=3D"margin-right:2px;margin-left:2px;padding=
-right:2px;padding-left:2px;border:1px solid rgb(214,214,214);background-co=
lor:rgba(0,0,0,0.027451);border-top-left-radius:3px;border-top-right-radius=
:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;display:i=
nline-block;color:rgb(0,0,0);font-family:dejavusans,'dejavu sans',a=
rial,sans-serif"><span style=3D"line-height:normal;white-space:nowrap;font-=
family:dejavusansmono,'dejavu sans mono',courier,monospace">std::ad=
dressof(*t_)</span></span><span style=3D"color:rgb(0,0,0);font-family:dejav=
usans,'dejavu sans',arial,sans-serif">.</span></div><div><span styl=
e=3D"color:rgb(0,0,0);font-family:dejavusans,'dejavu sans',arial,sa=
ns-serif"><br></span></div><div><span style=3D"color:rgb(0,0,0);font-family=
:dejavusans,'dejavu sans',arial,sans-serif">Besides being shorter, =
simpler, and "obviously correct" for non-class types, this would =
elegantly avoid the current problem for class types when </span><span style=
=3D"color:rgb(0,0,0)"><font face=3D"courier new, monospace">decltype(t_.get=
())</font></span><span style=3D"color:rgb(0,0,0);font-family:dejavusans,=
9;dejavu sans',arial,sans-serif"> is not convertible to=C2=A0</span><sp=
an style=3D"color:rgb(0,0,0)"><font face=3D"courier new, monospace">element=
_type</font></span><span style=3D"color:rgb(0,0,0);font-family:dejavusans,&=
#39;dejavu sans',arial,sans-serif">.</span></div></div></blockquote><di=
v>=C2=A0<br>That wouldn't work for null pointers.</div></div></blockquo=
te><div><br></div></span><div>Good point. To work with null pointers, I'=
;d want</div><div><br></div><div><font face=3D"monospace, monospace">templa=
te<typename T></font></div><div><font face=3D"monospace, monospace">a=
uto <i>GETPOINTER</i>(T&& t) {</font></div><div><font face=3D"monos=
pace, monospace">=C2=A0 =C2=A0 return t ? std::addressof(*t) : nullptr;</fo=
nt></div><div><font face=3D"monospace, monospace">}</font></div></div></div=
></div></blockquote><div><br></div></span><div>The problem is that not all =
pointer-like types are contextually convertible to <span style=3D"font-fami=
ly:monospace,monospace">`bool`</span>.<br></div></div></div></div></blockqu=
ote><div><br></div><div>I'd say either that yes they are; or else that =
you could replace <font face=3D"monospace, monospace">t</font> above with <=
font face=3D"monospace, monospace">t !=3D nullptr</font> or even <font face=
=3D"monospace, monospace">t !=3D decltype(t){}</font> without loss of sense=
.. I don't have a particular preference among those three options.</div>=
<div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px =
0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-l=
eft-style:solid;padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extr=
a"><div class=3D"gmail_quote"><div></div><span class=3D"gmail-"><div>=C2=A0=
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;b=
order-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:s=
olid;padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><div cla=
ss=3D"gmail_quote"><div>where this doesn't really need to be a library =
function in its own right, but maybe it should be. (Similar to how <i><font=
face=3D"monospace, monospace">INVOKE</font></i> wasn't a library funct=
ion in its own right for a long time, but as of C++17 there were so many ot=
her functions defined in terms of <font face=3D"monospace, monospace"><i>IN=
VOKE</i></font> that it metamorphosed into <font face=3D"monospace, monospa=
ce">std::invoke</font>. Maybe getpointer should just skip the <font face=3D=
"monospace, monospace"><i>GETPOINTER</i></font> phase entirely.)</div><span=
></span></div></div></div></blockquote><div><br></div></span><div>I think <=
span style=3D"font-family:monospace,monospace">`get_pointer`</span> would b=
e useful for non-standard libraries as well, so I think it should be a libr=
ary function.<br></div></div></div></div></blockquote><div><br></div><div>F=
air. But IMO, just like <font face=3D"monospace, monospace"><i>INVOKE</i></=
font>/<font face=3D"monospace, monospace">std::invoke</font>, it should hav=
e well-defined behavior that is provided 100% by the implementation; it sho=
uld not require non-gurus to understand it, implement it, or otherwise inte=
ract with it except to=C2=A0<i>call</i>=C2=A0it.</div><div><br></div><div>=
=C2=A0<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-le=
ft-style:solid;padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra=
"><div class=3D"gmail_quote"><div></div><span class=3D"gmail-"><blockquote =
class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1=
px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:=
1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"=
><span><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;=
border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:=
solid;padding-left:1ex"><div dir=3D"ltr"><div>Besides, I was only using <sp=
an style=3D"font-family:'courier new',monospace">`propagate_const`<=
/span> as an example of where <span style=3D"font-family:'courier new&#=
39;,monospace">`get_pointer`</span> would be useful; it would use <span sty=
le=3D"font-family:'courier new',monospace">`get_pointer`</span> ins=
tead of requiring compatible classes to have a <span style=3D"font-family:&=
#39;courier new',monospace">`get`</span> member function that returns a=
pointer.<br></div></div></blockquote><div><br></div></span><div>Right. I&#=
39;m saying (and I think you're agreeing) that proliferating a Java-sty=
le zoo of interfaces (and especially implicit, non-inheritance-based interf=
aces) in C++ would be a bad thing. I don't want my smart-pointer types =
to have to implement a <font face=3D"monospace, monospace">.get()</font> me=
mber function in addition to the natural <font face=3D"monospace, monospace=
">operator*</font> that they've already got, just in order to enable so=
me standard container or algorithm. Instead, I want the standard containers=
and algorithms to work with all pointerish types the same way, generically=
, without adding additional requirements that the smart-pointer-implementor=
needs to know about and implement correctly.</div><span></span></div></div=
></div></blockquote><div>=C2=A0<br></div></span><div>Yep. As I alluded to, =
the problem is that pointer-like types may or may not implement the <span s=
tyle=3D"font-family:monospace,monospace"><a href=3D"http://en.cppreference.=
com/w/cpp/concept/NullablePointer" target=3D"_blank">NullablePointer</a></s=
pan> concept. Thus, <span style=3D"font-family:monospace,monospace">`operat=
or*`<font face=3D"arial,helvetica,sans-serif"> cannot be reliably used in t=
his way.</font></span></div></div></div></div></blockquote><div><br></div><=
div><font face=3D"monospace, monospace"><a href=3D"http://en.cppreference.c=
om/w/cpp/concept/NullablePointer">NullablePointer</a></font> does not actua=
lly require dereferenceability=C2=A0=E2=80=94 which IMHO means it's hor=
ribly misnamed, but let that lie for now.</div><div>I agree that <font face=
=3D"monospace, monospace"><a href=3D"http://en.cppreference.com/w/cpp/conce=
pt/NullablePointer">NullablePointer</a></font> doesn't model anything r=
emotely resembling "pointer-like". However, I claim that anything=
"pointer-like" must at least conditionally support dereferencing=
; that's what it means for A to "point to" B. "A points =
to B" means that when you dereference A, you get B.</div><div><br></di=
v><div>Now, there is still a problem, even in my happy world where all &quo=
t;pointer-like" types implement <font face=3D"monospace, monospace">op=
erator*</font>. The problem is that sometimes a pointer can be non-null and=
<i>still</i> not point to an object. For example:</div><div><br></div><div=
><font face=3D"monospace, monospace">=C2=A0 =C2=A0 std::vector<int> a=
(42);</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 in=
t *p =3D &a[0] + 42;<br></font></div><div><font face=3D"monospace, mono=
space">=C2=A0 =C2=A0 assert(p !=3D decltype(p){});</font></div><div><font f=
ace=3D"monospace, monospace">=C2=A0 =C2=A0 // Nevertheless we are not allow=
ed to call std::addressof(*p) as far as I know</font></div><div><font face=
=3D"monospace, monospace"><br></font></div><div><div><font face=3D"monospac=
e, monospace">=C2=A0 =C2=A0 auto it =3D a.end();<br></font></div><div><font=
face=3D"monospace, monospace">=C2=A0 =C2=A0 assert(it !=3D decltype(it){})=
;</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 // Nev=
ertheless we are not allowed to call std::addressof(*it)<br></font></div></=
div><div><br></div><div>What behavior would you want for <font face=3D"mono=
space, monospace">std::get_pointer(p)</font>=C2=A0(respectively=C2=A0<font =
face=3D"monospace, monospace">std::get_pointer(it)</font>) in this case?</d=
iv><div>I suspect you'd want <font face=3D"monospace, monospace">std::g=
et_pointer(p) =3D=3D p</font> somehow. I hope you're <i>not</i> going t=
o claim that <font face=3D"monospace, monospace">decltype(it)</font> is &qu=
ot;not a pointer-like type"; but I'm not sure it's implementab=
le to mandate that <font face=3D"monospace, monospace">std::get_pointer(it)=
</font>=C2=A0consistently return either=C2=A0<font face=3D"monospace, monos=
pace">nullptr</font> or <font face=3D"monospace, monospace">p</font>.</div>=
<div><br></div><div>By the way, does your intuition agree with mine that <b=
><font face=3D"monospace, monospace">std::exception_ptr</font> is not a &qu=
ot;pointer-like type"</b>? =C2=A0(It does model <font face=3D"monospac=
e, monospace">NullablePointer</font>, but it is not dereferenceable and doe=
sn't "point to" anything in a meaningful sense.)</div><div>Al=
ternatively, if you think it <i>is</i> a pointer-like type, what should be =
returned by <font face=3D"monospace, monospace">std::get_pointer(std::curre=
nt_exception())</font>?</div><div><br></div><div>=E2=80=93Arthur</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/CADvuK0L1TmJOQwnZYub177%3DqD13ygANeg4=
h_CuuJYW1Uhhaz3Q%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0L1TmJOQw=
nZYub177%3DqD13ygANeg4h_CuuJYW1Uhhaz3Q%40mail.gmail.com</a>.<br />
--001a11443096a2fa9f0547e7dde9--
.
Author: Joseph Thomson <joseph.thomson@gmail.com>
Date: Tue, 7 Feb 2017 13:51:11 +0800
Raw View
--f403045d6158db25d40547ea55b3
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Tue, Feb 7, 2017 at 10:54 AM, Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
wrote:
> On Mon, Feb 6, 2017 at 4:03 PM, Joseph Thomson <joseph.thomson@gmail.com>
> wrote:
>
>> On Tue, Feb 7, 2017 at 4:52 AM, Arthur O'Dwyer <arthur.j.odwyer@gmail.co=
m
>> > wrote:
>>
>>> On Tue, Jan 31, 2017 at 8:52 PM, <joseph.thomson@gmail.com> wrote:
>>>
>>>> On Wednesday, 1 February 2017 08:23:32 UTC+8, Arthur O'Dwyer wrote:
>>>>>
>>>>> On Tuesday, January 31, 2017 at 6:26:30 AM UTC-8, joseph....@gmail.co=
m
>>>>> wrote:
>>>>>>
>>>>>> There is currently no uniform way to retrieve a pointer from an
>>>>>> arbitrary pointer or pointer-like object. One real example where suc=
h a
>>>>>> feature would be useful is the proposed `propagate_const` wrapper, w=
hich
>>>>>> currently requires compatible class types to have a `get` member fun=
ction.
>>>>>> This is an intrusive requirement, that the user may not even have th=
e
>>>>>> capacity to meet.
>>>>>
>>>>>
>>>>> http://en.cppreference.com/w/cpp/experimental/propagate_const/get
>>>>>
>>>>> I agree that the current text there seems stupid. It currently says
>>>>> that the return value of t.get() ought to be:
>>>>> > If T is an object pointer type, then t_. Otherwise, t_.get().
>>>>> IMO it would be a strict usability improvement to say simply that
>>>>> t.get() returns
>>>>> > std::addressof(*t_).
>>>>>
>>>>> Besides being shorter, simpler, and "obviously correct" for non-class
>>>>> types, this would elegantly avoid the current problem for class types=
when
>>>>> decltype(t_.get()) is not convertible to element_type.
>>>>>
>>>>
>>>> That wouldn't work for null pointers.
>>>>
>>>
>>> Good point. To work with null pointers, I'd want
>>>
>>> template<typename T>
>>> auto *GETPOINTER*(T&& t) {
>>> return t ? std::addressof(*t) : nullptr;
>>> }
>>>
>>
>> The problem is that not all pointer-like types are contextually
>> convertible to `bool`.
>>
>
> I'd say either that yes they are; or else that you could replace t above
> with t !=3D nullptr or even t !=3D decltype(t){} without loss of sense. I
> don't have a particular preference among those three options.
>
My proposal was motivated by the creation of a "not null" pointer type
(which I'm either going to propose for inclusion in the standard or the
GSL), so I definitely think that it's possible for pointer-like types to
not be contextually convertible to `bool` (especially if, as you point out,
iterators are considered pointer-like).
>
>>
>>> where this doesn't really need to be a library function in its own
>>> right, but maybe it should be. (Similar to how *INVOKE* wasn't a
>>> library function in its own right for a long time, but as of C++17 ther=
e
>>> were so many other functions defined in terms of *INVOKE* that it
>>> metamorphosed into std::invoke. Maybe getpointer should just skip the
>>> *GETPOINTER* phase entirely.)
>>>
>>
>> I think `get_pointer` would be useful for non-standard libraries as
>> well, so I think it should be a library function.
>>
>
> Fair. But IMO, just like *INVOKE*/std::invoke, it should have
> well-defined behavior that is provided 100% by the implementation; it
> should not require non-gurus to understand it, implement it, or otherwise
> interact with it except to *call* it.
>
This seems reasonable. See my comments below.
>
>
>> Besides, I was only using `propagate_const` as an example of where
>>>> `get_pointer` would be useful; it would use `get_pointer` instead of
>>>> requiring compatible classes to have a `get` member function that
>>>> returns a pointer.
>>>>
>>>
>>> Right. I'm saying (and I think you're agreeing) that proliferating a
>>> Java-style zoo of interfaces (and especially implicit,
>>> non-inheritance-based interfaces) in C++ would be a bad thing. I don't =
want
>>> my smart-pointer types to have to implement a .get() member function in
>>> addition to the natural operator* that they've already got, just in
>>> order to enable some standard container or algorithm. Instead, I want t=
he
>>> standard containers and algorithms to work with all pointerish types th=
e
>>> same way, generically, without adding additional requirements that the
>>> smart-pointer-implementor needs to know about and implement correctly.
>>>
>>
>> Yep. As I alluded to, the problem is that pointer-like types may or may
>> not implement the NullablePointer
>> <http://en.cppreference.com/w/cpp/concept/NullablePointer> concept.
>> Thus, `operator*` cannot be reliably used in this way.
>>
>
> NullablePointer <http://en.cppreference.com/w/cpp/concept/NullablePointer=
>
> does not actually require dereferenceability =E2=80=94 which IMHO means i=
t's
> horribly misnamed, but let that lie for now.
> I agree that NullablePointer
> <http://en.cppreference.com/w/cpp/concept/NullablePointer> doesn't model
> anything remotely resembling "pointer-like". However, I claim that anythi=
ng
> "pointer-like" must at least conditionally support dereferencing; that's
> what it means for A to "point to" B. "A points to B" means that when you
> dereference A, you get B.
>
I agree. Probably shouldn't have brought up NullablePointer. What I am
really concerned with is that `T` is contextually convertible to `bool` and
that the result of this conversion indicates whether the pointer is null.
Now, there is still a problem, even in my happy world where all
> "pointer-like" types implement operator*. The problem is that sometimes a
> pointer can be non-null and *still* not point to an object. For example:
>
> std::vector<int> a(42);
> int *p =3D &a[0] + 42;
> assert(p !=3D decltype(p){});
> // Nevertheless we are not allowed to call std::addressof(*p) as far
> as I know
>
> auto it =3D a.end();
> assert(it !=3D decltype(it){});
> // Nevertheless we are not allowed to call std::addressof(*it)
>
> What behavior would you want for std::get_pointer(p) (respectively
> std::get_pointer(it)) in this case?
> I suspect you'd want std::get_pointer(p) =3D=3D p somehow. I hope you're =
*not*
> going to claim that decltype(it) is "not a pointer-like type"; but I'm
> not sure it's implementable to mandate that std::get_pointer(it) consiste=
ntly
> return either nullptr or p.
>
I had to think about this for a while. I think post-C++17, once contiguous
iterators are a thing, both `get_pointer(a.data() + a.size())` and
`get_pointer(a.end())` would return `a.data() + a.size()`. For
non-contiguous iterators, a past-the-end iterator is not guaranteed to
point to a memory address, so the behaviour of `get_pointer(a.end())` would
be undefined. As you point out, `&*p` gives undefined behaviour for
past-the-end iterators, so we need some other method to extract the
pointer. I suggest explicit conversion to `T*`. The contiguous iterator
proposal noted that they considered this, but some were worried that this
would *"[go] too far towards weakening the boundary between pointers and
iterators"*. I think this concern is misplaced.
By the way, does your intuition agree with mine that *std::exception_ptr is
> not a "pointer-like type"*? (It does model NullablePointer, but it is
> not dereferenceable and doesn't "point to" anything in a meaningful sense=
..)
> Alternatively, if you think it *is* a pointer-like type, what should be
> returned by std::get_pointer(std::current_exception())?
>
Yes, I agree that `exception_ptr` is not a pointer-like type, though
"pointer-like" is not a concept defined by the standard. If I were going to
standardize a PointerLike concept, I would probably do something like this:
an object `p` (and object `q` of the same type) is of PointerLike type if
for some type `T`:
- `static_cast<T*>(p)` is a valid expression
- `*p` is equivalent to `*static_cast<T*>(p)`
- `p.operator->()` is equivalent to `static_cast<T*>(p)`
- `p =3D=3D q` is equivalent to `static_cast<T*>(p) =3D=3D static_cast<T=
*>(q)`
- `p !=3D q` is equivalent to `!(p =3D=3D q)`
If `static_cast<T*>(p)` can return a null pointer, `p` should be
contextually convertible to `bool` to indicate this condition, but this is
not a requirement of a "pointer-like" type.
Note that under this definition, only InputIterator satisfies PointerLike,
as the expression `*p` must be of type `T&`, and Iterator doesn't define a
return type for `*p`.
Of course, I'm no language lawyer, so I have probably made incorrect
assumptions. However, defining the behaviour of "pointer-like" types in
terms of explicit conversion to `T*` seems like the best idea to me, since
it works both pointers and pointer-like types, including contiguous
iterators, without the need for ADL.
--=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/CAHocnE8c0uDcAtDHy9FVO1D1H8L7Z31qi%3DNHBoUYYiBOJ=
49YpA%40mail.gmail.com.
--f403045d6158db25d40547ea55b3
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On T=
ue, Feb 7, 2017 at 10:54 AM, Arthur O'Dwyer <span dir=3D"ltr"><<a hr=
ef=3D"mailto:arthur.j.odwyer@gmail.com" target=3D"_blank">arthur.j.odwyer@g=
mail.com</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding=
-left:1ex"><div dir=3D"ltr"><span class=3D"gmail-">On Mon, Feb 6, 2017 at 4=
:03 PM, Joseph Thomson <span dir=3D"ltr"><<a href=3D"mailto:joseph.thoms=
on@gmail.com" target=3D"_blank">joseph.thomson@gmail.com</a>></span> wro=
te:<br></span><div class=3D"gmail_extra"><div class=3D"gmail_quote"><span c=
lass=3D"gmail-"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=
=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><span class=
=3D"gmail-m_-4498339902504097115gmail-">On Tue, Feb 7, 2017 at 4:52 AM, Art=
hur O'Dwyer <span dir=3D"ltr"><<a href=3D"mailto:arthur.j.odwyer@gma=
il.com" target=3D"_blank">arthur.j.odwyer@gmail.com</a>></span> wrote:<b=
r><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;borde=
r-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><span>=
On Tue, Jan 31, 2017 at 8:52 PM, <span dir=3D"ltr"><<a href=3D"mailto:j=
oseph.thomson@gmail.com" target=3D"_blank">joseph.thomson@gmail.com</a>>=
</span> wrote:<br></span><div class=3D"gmail_extra"><div class=3D"gmail_quo=
te"><span><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8=
ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr=
">On Wednesday, 1 February 2017 08:23:32 UTC+8, Arthur O'Dwyer wrote:<=
blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-l=
eft:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr">On Tuesda=
y, January 31, 2017 at 6:26:30 AM UTC-8, <a>joseph....@gmail.com</a> wrote:=
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-=
left:1px solid rgb(204,204,204);padding-left:1ex">There is currently no uni=
form way to retrieve a pointer from an arbitrary pointer or pointer-like ob=
ject. One real example where such a feature would be useful is the proposed=
`propagate_const` wrapper, which currently requires compatible class types=
to have a `get` member function. This is an intrusive requirement, that th=
e user may not even have the capacity to meet.</blockquote><div><br></div><=
div><a href=3D"http://en.cppreference.com/w/cpp/experimental/propagate_cons=
t/get" rel=3D"nofollow" target=3D"_blank">http://en.cppreference.com/w/c<wb=
r>pp/experimental/propagate_cons<wbr>t/get</a><br></div><div><br></div><div=
>I agree that the current text there seems stupid. It currently says that t=
he return value of t.get() ought to be:</div><div>>=C2=A0<span style=3D"=
color:rgb(0,0,0);font-family:dejavusans,"dejavu sans",arial,sans-=
serif">If=C2=A0</span><code style=3D"background-color:transparent;color:rgb=
(0,0,0);font-family:dejavusansmono,"dejavu sans mono",courier,mon=
ospace">T</code><span style=3D"color:rgb(0,0,0);font-family:dejavusans,&quo=
t;dejavu sans",arial,sans-serif">=C2=A0is an object pointer type, then=
=C2=A0</span><span style=3D"background-color:rgba(0,0,0,0.027);border-width=
:1px;border-style:solid;border-color:rgb(214,214,214);border-radius:3px;mar=
gin-right:2px;margin-left:2px;padding-right:2px;padding-left:2px;display:in=
line-block;color:rgb(0,0,0);font-family:dejavusans,"dejavu sans",=
arial,sans-serif"><span style=3D"line-height:normal;white-space:nowrap;font=
-family:dejavusansmono,"dejavu sans mono",courier,monospace">t_</=
span></span><span style=3D"color:rgb(0,0,0);font-family:dejavusans,"de=
javu sans",arial,sans-serif">. Otherwise,=C2=A0</span><span style=3D"b=
ackground-color:rgba(0,0,0,0.027);border-width:1px;border-style:solid;borde=
r-color:rgb(214,214,214);border-radius:3px;margin-right:2px;margin-left:2px=
;padding-right:2px;padding-left:2px;display:inline-block;color:rgb(0,0,0);f=
ont-family:dejavusans,"dejavu sans",arial,sans-serif"><span style=
=3D"line-height:normal;white-space:nowrap;font-family:dejavusansmono,"=
dejavu sans mono",courier,monospace">t_.<span>get</span><span style=3D=
"color:rgb(0,128,0)">(</span><span style=3D"color:rgb(0,128,0)">)</span></s=
pan></span><span style=3D"color:rgb(0,0,0);font-family:dejavusans,"dej=
avu sans",arial,sans-serif">.</span><br></div><div>IMO it would be a s=
trict usability improvement to say simply that t.get() returns</div><div>&g=
t; <span style=3D"margin-right:2px;margin-left:2px;padding-right:2px;paddin=
g-left:2px;border-width:1px;border-style:solid;border-color:rgb(214,214,214=
);background-color:rgba(0,0,0,0.027);border-radius:3px;display:inline-block=
;color:rgb(0,0,0);font-family:dejavusans,"dejavu sans",arial,sans=
-serif"><span style=3D"line-height:normal;white-space:nowrap;font-family:de=
javusansmono,"dejavu sans mono",courier,monospace">std::addressof=
(*t_)</span></span><span style=3D"color:rgb(0,0,0);font-family:dejavusans,&=
quot;dejavu sans",arial,sans-serif">.</span></div><div><span style=3D"=
color:rgb(0,0,0);font-family:dejavusans,"dejavu sans",arial,sans-=
serif"><br></span></div><div><span style=3D"color:rgb(0,0,0);font-family:de=
javusans,"dejavu sans",arial,sans-serif">Besides being shorter, s=
impler, and "obviously correct" for non-class types, this would e=
legantly avoid the current problem for class types when </span><span style=
=3D"color:rgb(0,0,0)"><font face=3D"courier new, monospace">decltype(t_.get=
())</font></span><span style=3D"color:rgb(0,0,0);font-family:dejavusans,&qu=
ot;dejavu sans",arial,sans-serif"> is not convertible to=C2=A0</span><=
span style=3D"color:rgb(0,0,0)"><font face=3D"courier new, monospace">eleme=
nt_type</font></span><span style=3D"color:rgb(0,0,0);font-family:dejavusans=
,"dejavu sans",arial,sans-serif">.</span></div></div></blockquote=
><div>=C2=A0<br>That wouldn't work for null pointers.</div></div></bloc=
kquote><div><br></div></span><div>Good point. To work with null pointers, I=
'd want</div><div><br></div><div><font face=3D"monospace, monospace">te=
mplate<typename T></font></div><div><font face=3D"monospace, monospac=
e">auto <i>GETPOINTER</i>(T&& t) {</font></div><div><font face=3D"m=
onospace, monospace">=C2=A0 =C2=A0 return t ? std::addressof(*t) : nullptr;=
</font></div><div><font face=3D"monospace, monospace">}</font></div></div><=
/div></div></blockquote><div><br></div></span><div>The problem is that not =
all pointer-like types are contextually convertible to <span style=3D"font-=
family:monospace,monospace">`bool`</span>.<br></div></div></div></div></blo=
ckquote><div><br></div></span><div>I'd say either that yes they are; or=
else that you could replace <font face=3D"monospace, monospace">t</font> a=
bove with <font face=3D"monospace, monospace">t !=3D nullptr</font> or even=
<font face=3D"monospace, monospace">t !=3D decltype(t){}</font> without lo=
ss of sense. I don't have a particular preference among those three opt=
ions. </div><span class=3D"gmail-"></span></div></div></div></blockquote><d=
iv><br></div><div>My proposal was motivated by the creation of a "not =
null" pointer type (which I'm either going to propose for inclusio=
n in the standard or the GSL), so I definitely think that it's possible=
for pointer-like types to not be contextually convertible to <span style=
=3D"font-family:monospace,monospace">`bool`</span> (especially if, as you p=
oint out, iterators are considered pointer-like).<br></div><div>=C2=A0</div=
><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border=
-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div cl=
ass=3D"gmail_extra"><div class=3D"gmail_quote"><span class=3D"gmail-"><bloc=
kquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:=
1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div class=3D=
"gmail_extra"><div class=3D"gmail_quote"><div></div><span class=3D"gmail-m_=
-4498339902504097115gmail-"><div>=C2=A0</div><blockquote class=3D"gmail_quo=
te" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204=
);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><div class=
=3D"gmail_quote"><div>where this doesn't really need to be a library fu=
nction in its own right, but maybe it should be. (Similar to how <i><font f=
ace=3D"monospace, monospace">INVOKE</font></i> wasn't a library functio=
n in its own right for a long time, but as of C++17 there were so many othe=
r functions defined in terms of <font face=3D"monospace, monospace"><i>INVO=
KE</i></font> that it metamorphosed into <font face=3D"monospace, monospace=
">std::invoke</font>. Maybe getpointer should just skip the <font face=3D"m=
onospace, monospace"><i>GETPOINTER</i></font> phase entirely.)</div><span><=
/span></div></div></div></blockquote><div><br></div></span><div>I think <sp=
an style=3D"font-family:monospace,monospace">`get_pointer`</span> would be =
useful for non-standard libraries as well, so I think it should be a librar=
y function.<br></div></div></div></div></blockquote><div><br></div></span><=
div>Fair. But IMO, just like <font face=3D"monospace, monospace"><i>INVOKE<=
/i></font>/<font face=3D"monospace, monospace">std::invoke</font>, it shoul=
d have well-defined behavior that is provided 100% by the implementation; i=
t should not require non-gurus to understand it, implement it, or otherwise=
interact with it except to=C2=A0<i>call</i>=C2=A0it.</div></div></div></di=
v></blockquote><div><br></div>This seems reasonable. See my comments below.=
<br><span class=3D"gmail-"><div><div>=C2=A0</div><span class=3D"gmail-"></s=
pan></div></span><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px =
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=
=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><span class=
=3D"gmail-"><div>=C2=A0<br></div><blockquote class=3D"gmail_quote" style=3D=
"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-le=
ft:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quo=
te"><div></div><span class=3D"gmail-m_-4498339902504097115gmail-"><blockquo=
te class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px =
solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gma=
il_extra"><div class=3D"gmail_quote"><span><blockquote class=3D"gmail_quote=
" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);=
padding-left:1ex"><div dir=3D"ltr"><div>Besides, I was only using <span sty=
le=3D"font-family:"courier new",monospace">`propagate_const`</spa=
n> as an example of where <span style=3D"font-family:"courier new"=
;,monospace">`get_pointer`</span> would be useful; it would use <span style=
=3D"font-family:"courier new",monospace">`get_pointer`</span> ins=
tead of requiring compatible classes to have a <span style=3D"font-family:&=
quot;courier new",monospace">`get`</span> member function that returns=
a pointer.<br></div></div></blockquote><div><br></div></span><div>Right. I=
'm saying (and I think you're agreeing) that proliferating a Java-s=
tyle zoo of interfaces (and especially implicit, non-inheritance-based inte=
rfaces) in C++ would be a bad thing. I don't want my smart-pointer type=
s to have to implement a <font face=3D"monospace, monospace">.get()</font> =
member function in addition to the natural <font face=3D"monospace, monospa=
ce">operator*</font> that they've already got, just in order to enable =
some standard container or algorithm. Instead, I want the standard containe=
rs and algorithms to work with all pointerish types the same way, generical=
ly, without adding additional requirements that the smart-pointer-implement=
or needs to know about and implement correctly.</div><span></span></div></d=
iv></div></blockquote><div>=C2=A0<br></div></span><div>Yep. As I alluded to=
, the problem is that pointer-like types may or may not implement the <span=
style=3D"font-family:monospace,monospace"><a href=3D"http://en.cppreferenc=
e.com/w/cpp/concept/NullablePointer" target=3D"_blank">NullablePointer</a><=
/span> concept. Thus, <span style=3D"font-family:monospace,monospace">`oper=
ator*`<font face=3D"arial,helvetica,sans-serif"> cannot be reliably used in=
this way.</font></span></div></div></div></div></blockquote><div><br></div=
></span><div><font face=3D"monospace, monospace"><a href=3D"http://en.cppre=
ference.com/w/cpp/concept/NullablePointer" target=3D"_blank">NullablePointe=
r</a></font> does not actually require dereferenceability=C2=A0=E2=80=94 wh=
ich IMHO means it's horribly misnamed, but let that lie for now.</div><=
div>I agree that <font face=3D"monospace, monospace"><a href=3D"http://en.c=
ppreference.com/w/cpp/concept/NullablePointer" target=3D"_blank">NullablePo=
inter</a></font> doesn't model anything remotely resembling "point=
er-like". However, I claim that anything "pointer-like" must=
at least conditionally support dereferencing; that's what it means for=
A to "point to" B. "A points to B" means that when you=
dereference A, you get B.</div></div></div></div></blockquote><div>=C2=A0<=
br></div><div>I agree. Probably shouldn't have brought up <span style=
=3D"font-family:monospace,monospace">NullablePointer</span>. What I am real=
ly concerned with is that <span style=3D"font-family:monospace,monospace">`=
T`</span> is contextually convertible to <span style=3D"font-family:monospa=
ce,monospace">`bool`</span> and that the result of this conversion indicate=
s whether the pointer is null.<br></div><div><br></div><blockquote class=3D=
"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(2=
04,204,204);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><=
div class=3D"gmail_quote"><div></div><div>Now, there is still a problem, ev=
en in my happy world where all "pointer-like" types implement <fo=
nt face=3D"monospace, monospace">operator*</font>. The problem is that some=
times a pointer can be non-null and <i>still</i> not point to an object. Fo=
r example:</div><div><br></div><div><font face=3D"monospace, monospace">=C2=
=A0 =C2=A0 std::vector<int> a(42);</font></div><div><font face=3D"mon=
ospace, monospace">=C2=A0 =C2=A0 int *p =3D &a[0] + 42;<br></font></div=
><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 assert(p !=3D declt=
ype(p){});</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=
=A0 // Nevertheless we are not allowed to call std::addressof(*p) as far as=
I know</font></div><div><font face=3D"monospace, monospace"><br></font></d=
iv><div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 auto it =3D =
a.end();<br></font></div><div><font face=3D"monospace, monospace">=C2=A0 =
=C2=A0 assert(it !=3D decltype(it){});</font></div><div><font face=3D"monos=
pace, monospace">=C2=A0 =C2=A0 // Nevertheless we are not allowed to call s=
td::addressof(*it)<br></font></div></div><div><br></div><div>What behavior =
would you want for <font face=3D"monospace, monospace">std::get_pointer(p)<=
/font>=C2=A0(<wbr>respectively=C2=A0<font face=3D"monospace, monospace">std=
::get_pointer(<wbr>it)</font>) in this case?</div><div>I suspect you'd =
want <font face=3D"monospace, monospace">std::get_pointer(p) =3D=3D p</font=
> somehow. I hope you're <i>not</i> going to claim that <font face=3D"m=
onospace, monospace">decltype(it)</font> is "not a pointer-like type&q=
uot;; but I'm not sure it's implementable to mandate that <font fac=
e=3D"monospace, monospace">std::get_pointer(it)</font>=C2=A0<wbr>consistent=
ly return either=C2=A0<font face=3D"monospace, monospace">nullptr</font> or=
<font face=3D"monospace, monospace">p</font>.</div></div></div></div></blo=
ckquote><div><br></div><div>I had to think about this for a while. I think =
post-C++17, once contiguous iterators are a thing, both <span style=3D"font=
-family:monospace,monospace">`get_pointer(a.data() + a.size())`</span> and =
<span style=3D"font-family:monospace,monospace">`get_pointer(a.end())`</spa=
n> would return <span style=3D"font-family:monospace,monospace">`a.data() +=
a.size()`</span>. For non-contiguous iterators, a past-the-end iterator is=
not guaranteed to point to a memory address, so the behaviour of <span sty=
le=3D"font-family:monospace,monospace">`get_pointer(a.end())`</span> would =
be undefined. As you point out, <span style=3D"font-family:monospace,monosp=
ace">`&*p`</span> gives undefined behaviour for past-the-end iterators,=
so we need some other method to extract the pointer. I suggest explicit co=
nversion to <span style=3D"font-family:monospace,monospace">`T*`</span>. Th=
e contiguous iterator proposal noted that they considered this, but some we=
re worried that this would <i>"[go] too far towards weakening the bou=
ndary between pointers and iterators"</i>. I think this concern is mis=
placed.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px =
0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div=
dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><div>By =
the way, does your intuition agree with mine that <b><font face=3D"monospac=
e, monospace">std::exception_ptr</font> is not a "pointer-like type&qu=
ot;</b>? =C2=A0(It does model <font face=3D"monospace, monospace">NullableP=
ointer</font>, but it is not dereferenceable and doesn't "point to=
" anything in a meaningful sense.)</div><div>Alternatively, if you thi=
nk it <i>is</i> a pointer-like type, what should be returned by <font face=
=3D"monospace, monospace">std::get_pointer(std::current_<wbr>exception())</=
font>?</div></div></div></div></blockquote><div><br></div><div>Yes, I agree=
that <span style=3D"font-family:monospace,monospace">`exception_ptr`</span=
> is not a pointer-like type, though "pointer-like" is not a conc=
ept defined by the standard. If I were going to standardize a <span style=
=3D"font-family:monospace,monospace">PointerLike</span> concept, I would pr=
obably do something like this: an object <span style=3D"font-family:monospa=
ce,monospace">`p`</span> (and object <span style=3D"font-family:monospace,m=
onospace">`q`</span> of the same type) is of <span style=3D"font-family:mon=
ospace,monospace">PointerLike</span> type if for some type <span style=3D"f=
ont-family:monospace,monospace">`T`</span>:<br></div><div><ul><li><span sty=
le=3D"font-family:monospace,monospace">`static_cast<T*>(p)`</span> is=
a valid expression<br><span style=3D"font-family:monospace,monospace"></sp=
an></li><li><span style=3D"font-family:monospace,monospace">`*p`</span> is =
equivalent to <span style=3D"font-family:monospace,monospace">`*static_cast=
<T*>(p)`</span></li><li><span style=3D"font-family:monospace,monospac=
e">`p.operator->()`</span><span style=3D"font-family:arial,helvetica,san=
s-serif"> is equivalent to </span><span style=3D"font-family:monospace,mono=
space">`static_cast<T*>(p)`<br></span></li><li><span style=3D"font-fa=
mily:monospace,monospace">`p =3D=3D q`</span> is equivalent to <span style=
=3D"font-family:monospace,monospace"><span style=3D"font-family:monospace,m=
onospace">`static_cast<T*>(</span>p) =3D=3D </span><span style=3D"fon=
t-family:monospace,monospace"><span style=3D"font-family:monospace,monospac=
e">static_cast<T*>(</span>q)`</span></li><li><span style=3D"font-fami=
ly:monospace,monospace">`p !=3D q`</span> is equivalent to <span style=3D"f=
ont-family:monospace,monospace">`!(p =3D=3D q)`</span></li></ul>If <span st=
yle=3D"font-family:monospace,monospace">`static_cast<T*>(p)`<font fac=
e=3D"arial,helvetica,sans-serif"> can return a null pointer, `p` should be =
contextually convertible to `bool` to indicate this condition, but this is =
not a requirement of a "pointer-like" type.<br><br></font></span>=
</div><div><span style=3D"font-family:monospace,monospace"><font face=3D"ar=
ial,helvetica,sans-serif">Note that under this definition, only </font>Inpu=
tIterator<font face=3D"arial,helvetica,sans-serif"> satisfies </font>Pointe=
rLike<font face=3D"arial,helvetica,sans-serif">, as the expression </font>`=
*p`<font face=3D"arial,helvetica,sans-serif"> must be of type </font>`T&=
;`<font face=3D"arial,helvetica,sans-serif">, and </font>Iterator<font face=
=3D"arial,helvetica,sans-serif"> doesn't define a return type for </fon=
t>`*p`<font face=3D"arial,helvetica,sans-serif">.<br></font></span></div><d=
iv><span style=3D"font-family:monospace,monospace"><font face=3D"arial,helv=
etica,sans-serif"><br></font></span></div><div><span style=3D"font-family:m=
onospace,monospace"><font face=3D"arial,helvetica,sans-serif">Of course, I&=
#39;m no language lawyer, so I have probably made incorrect assumptions. Ho=
wever, defining the behaviour of "pointer-like" types in terms of=
explicit conversion to </font>`T*`<font face=3D"arial,helvetica,sans-serif=
"> seems like the best idea to me, since it works both pointers and pointer=
-like types, including contiguous iterators, without the need for ADL.<br><=
/font></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/CAHocnE8c0uDcAtDHy9FVO1D1H8L7Z31qi%3D=
NHBoUYYiBOJ49YpA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHocnE8c0uDcAt=
DHy9FVO1D1H8L7Z31qi%3DNHBoUYYiBOJ49YpA%40mail.gmail.com</a>.<br />
--f403045d6158db25d40547ea55b3--
.
Author: "Arthur O'Dwyer" <arthur.j.odwyer@gmail.com>
Date: Wed, 15 Feb 2017 00:13:16 -0800
Raw View
--f403045f1e92b6756d05488d40e2
Content-Type: text/plain; charset=UTF-8
On Mon, Feb 6, 2017 at 9:51 PM, Joseph Thomson <joseph.thomson@gmail.com>
wrote:
> On Tue, Feb 7, 2017 at 10:54 AM, Arthur O'Dwyer <arthur.j.odwyer@gmail.com
> > wrote:
>
>> On Mon, Feb 6, 2017 at 4:03 PM, Joseph Thomson <joseph.thomson@gmail.com>
>> wrote:
>>
>>> On Tue, Feb 7, 2017 at 4:52 AM, Arthur O'Dwyer <
>>> arthur.j.odwyer@gmail.com> wrote:
>>>
>>>> On Tue, Jan 31, 2017 at 8:52 PM, <joseph.thomson@gmail.com> wrote:
>>>>
>>>>> On Wednesday, 1 February 2017 08:23:32 UTC+8, Arthur O'Dwyer wrote:
>>>>>>
>>>>>> On Tuesday, January 31, 2017 at 6:26:30 AM UTC-8,
>>>>>> joseph....@gmail.com wrote:
>>>>>>>
>>>>>>> There is currently no uniform way to retrieve a pointer from an
>>>>>>> arbitrary pointer or pointer-like object. One real example where such a
>>>>>>> feature would be useful is the proposed `propagate_const` wrapper, which
>>>>>>> currently requires compatible class types to have a `get` member function.
>>>>>>> This is an intrusive requirement, that the user may not even have the
>>>>>>> capacity to meet.
>>>>>>
>>>>>>
>>>>>> http://en.cppreference.com/w/cpp/experimental/propagate_const/get
>>>>>>
>>>>>> I agree that the current text there seems stupid. It currently says
>>>>>> that the return value of t.get() ought to be:
>>>>>> > If T is an object pointer type, then t_. Otherwise, t_.get().
>>>>>> IMO it would be a strict usability improvement to say simply that
>>>>>> t.get() returns
>>>>>> > std::addressof(*t_).
>>>>>>
>>>>>> Besides being shorter, simpler, and "obviously correct" for non-class
>>>>>> types, this would elegantly avoid the current problem for class types when
>>>>>> decltype(t_.get()) is not convertible to element_type.
>>>>>>
>>>>>
>>>>> That wouldn't work for null pointers.
>>>>>
>>>>
>>>> Good point. To work with null pointers, I'd want
>>>>
>>>> template<typename T>
>>>> auto *GETPOINTER*(T&& t) {
>>>> return t ? std::addressof(*t) : nullptr;
>>>> }
>>>>
>>>
>>> The problem is that not all pointer-like types are contextually
>>> convertible to `bool`.
>>>
>>
>> I'd say either that yes they are; or else that you could replace t above
>> with t != nullptr or even t != decltype(t){} without loss of sense. I
>> don't have a particular preference among those three options.
>>
>
> My proposal was motivated by the creation of a "not null" pointer type
> (which I'm either going to propose for inclusion in the standard or the
> GSL), so I definitely think that it's possible for pointer-like types to
> not be contextually convertible to `bool` (especially if, as you point
> out, iterators are considered pointer-like).
>
My kneejerk reaction is that even a "never null" pointer type ought to be
contextually convertible to bool. Its conversion function might be as
simple as
constexpr operator bool() const noexcept { return true; }
but it should still exist; otherwise you wouldn't be able to test the
pointer with "if (p)", which would make it unnecessarily awkward to drop
into existing codebases.
However, prior art seems to fall on the side of not allowing comparison of
known-non-null things with null things:
- Dropbox's nn <https://github.com/dropbox/nn/blob/master/nn.hpp#L96>
doesn't provide operator bool()
- GSL's not_null
<https://github.com/Microsoft/GSL/blob/master/include/gsl/gsl#L72> doesn't
provide operator bool(), nor even relational operators == !=
- Martin Moene's not_null
<https://github.com/martinmoene/gsl-lite/blob/master/include/gsl/gsl-lite.h#L856>
doesn't provide operator bool()
Now, we could still do something like
template<typename T>
auto GETPOINTER(T&& t) {
if constexpr(is_convertible_v<T&&, bool>) {
return bool(t) ? std::addressof(*t) : nullptr;
}
return std::addressof(*t);
}
Question, mostly whimsical: What would you expect to happen if I provided
an AlwaysNull<T> type that was the complementary type to NotNull<T>? That
is,
int i = 42;
AlwaysNull<int *> an = nullptr; // ok
AlwaysNull<int *> an2 = &i; // runtime error
if (an) { ... } // compile-time error: AlwaysNull<int *> is not
convertible to bool because "that would be silly
<https://github.com/dropbox/nn/blob/master/nn.hpp#L93>"
If this happened, would you want GETPOINTER(an) to "do the right thing" and
return nullptr, or would you want it to have undefined behavior, or what?
> Now, there is still a problem, even in my happy world where all
>> "pointer-like" types implement operator*. The problem is that sometimes
>> a pointer can be non-null and *still* not point to an object. For
>> example:
>>
>> std::vector<int> a(42);
>> int *p = &a[0] + 42;
>> assert(p != decltype(p){});
>> // Nevertheless we are not allowed to call std::addressof(*p) as far
>> as I know
>>
>> auto it = a.end();
>> assert(it != decltype(it){});
>> // Nevertheless we are not allowed to call std::addressof(*it)
>>
>> What behavior would you want for std::get_pointer(p) (respectively
>> std::get_pointer(it)) in this case?
>> I suspect you'd want std::get_pointer(p) == p somehow. I hope you're
>> *not* going to claim that decltype(it) is "not a pointer-like type"; but
>> I'm not sure it's implementable to mandate that std::get_pointer(it)
>> consistently return either nullptr or p.
>>
>
> I had to think about this for a while. I think post-C++17, once contiguous
> iterators are a thing, both `get_pointer(a.data() + a.size())` and
> `get_pointer(a.end())` would return `a.data() + a.size()`. For
> non-contiguous iterators, a past-the-end iterator is not guaranteed to
> point to a memory address, so the behaviour of `get_pointer(a.end())`
> would be undefined. As you point out, `&*p` gives undefined behaviour for
> past-the-end iterators, so we need some other method to extract the
> pointer. I suggest explicit conversion to `T*`. The contiguous iterator
> proposal noted that they considered this, but some were worried that this
> would *"[go] too far towards weakening the boundary between pointers and
> iterators"*. I think this concern is misplaced.
>
I don't see any reason to define the behavior of GETPOINTER(a.end()) given
that there flatly *is no object* at any memory address that could
reasonably be associated with a.end(). If I understand correctly, we're in
agreement that GETPOINTER(a.end()) should be undefined for e.g. std::list<int>
a; we're only in disagreement about whether it should be defined for
std::vector and std::array.
>
> By the way, does your intuition agree with mine that *std::exception_ptr
>> is not a "pointer-like type"*? (It does model NullablePointer, but it
>> is not dereferenceable and doesn't "point to" anything in a meaningful
>> sense.)
>> Alternatively, if you think it *is* a pointer-like type, what should be
>> returned by std::get_pointer(std::current_exception())?
>>
>
> Yes, I agree that `exception_ptr` is not a pointer-like type, though
> "pointer-like" is not a concept defined by the standard. If I were going to
> standardize a PointerLike concept, I would probably do something like
> this: an object `p` (and object `q` of the same type) is of PointerLike
> type if for some type `T`:
>
> - `static_cast<T*>(p)` is a valid expression
> - `*p` is equivalent to `*static_cast<T*>(p)`
> - `p.operator->()` is equivalent to `static_cast<T*>(p)`
> - `p == q` is equivalent to `static_cast<T*>(p) == static_cast<T*>(q)`
> - `p != q` is equivalent to `!(p == q)`
>
> I would say simply
template<typename T>
concept bool PointerLike() {
return requires(T p) {
{ *p };
};
}
template<typename T>
concept bool NullablePointerLike() {
return PointerLike<T>() && requires(T p) {
{ p } -> bool;
};
}
I definitely would not expect static_cast<T*>(p) to work; for example it
doesn't work for std::shared_ptr
<http://en.cppreference.com/w/cpp/memory/shared_ptr> or std::unique_ptr
<http://en.cppreference.com/w/cpp/memory/unique_ptr>, which IMNSHO
certainly ought to be considered "pointer-like types".
More weakly, I wouldn't necessarily expect p == q or p != q to work. There
are some algorithms that might require both PointerLike and
EqualityComparable, but I can think of many algorithms (e.g. iter_swap)
that require PointerLike *without* EqualityComparable. That said, I can't
off the top of my head think of any "pointer-like" types that don't support
the relational operators except for the GSL's nn<int*>
<https://github.com/Microsoft/GSL/blob/master/include/gsl/gsl#L72> (and I
can only imagine that that was a horrific oversight).
Here is a table of the operations we've been discussing, and their
well-formedness for a bunch of relevant types, listed roughly from most to
least "pointer-like" IMHO. Feel free to extend it with more rows and/or
columns!
A B C D E F
int* Y Y Y Y . Y
shared_ptr<int> Y . Y Y Y Y
unique_ptr<int> Y . Y Y Y Y
Dropbox nn<int*> . Y Y Y . Y
Dropbox nn<shared_ptr<int>> . . Y Y Y Y
gsl::not_null<int*> . Y . Y Y .
std::vector<int>::iterator . . . Y . Y
std::list<int>::iterator . . . Y . Y
istream_iterator<int> . . . Y . Y
ostream_iterator<int> . . . Y . .
std::nullptr_t Y Y Y . . Y
void* Y Y Y . . Y
std::exception_ptr Y . Y . . Y
std::optional<int> Y . . Y . Y
std::future<int> . . . . Y .
std::reference_wrapper<int> . . . . Y Y
A: static_cast<bool>(p)
B: static_cast<int*>(p)
C: p == nullptr
D: *p
E: p.get()
F: p == q
--
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/CADvuK0LwSa2kEj1e-RPcw8%3DPFHjs7JXMJZ-twygGZKg0W4jJrA%40mail.gmail.com.
--f403045f1e92b6756d05488d40e2
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Mon, Feb 6, 2017 at 9:51 PM, Joseph Thomson <span dir=
=3D"ltr"><<a href=3D"mailto:joseph.thomson@gmail.com" target=3D"_blank">=
joseph.thomson@gmail.com</a>></span> wrote:<br><div class=3D"gmail_extra=
"><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"mar=
gin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,2=
04);border-left-style:solid;padding-left:1ex"><div dir=3D"ltr"><div class=
=3D"gmail_extra"><div class=3D"gmail_quote"><span class=3D"gmail-">On Tue, =
Feb 7, 2017 at 10:54 AM, Arthur O'Dwyer <span dir=3D"ltr"><<a href=
=3D"mailto:arthur.j.odwyer@gmail.com" target=3D"_blank">arthur.j.odwyer@gma=
il.com</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"=
margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;bord=
er-left-color:rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><span cla=
ss=3D"gmail-m_4969974058834108480gmail-">On Mon, Feb 6, 2017 at 4:03 PM, Jo=
seph Thomson <span dir=3D"ltr"><<a href=3D"mailto:joseph.thomson@gmail.c=
om" target=3D"_blank">joseph.thomson@gmail.com</a>></span> wrote:<br></s=
pan><div class=3D"gmail_extra"><div class=3D"gmail_quote"><span class=3D"gm=
ail-m_4969974058834108480gmail-"><blockquote class=3D"gmail_quote" style=3D=
"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;bor=
der-left-color:rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div cla=
ss=3D"gmail_extra"><div class=3D"gmail_quote"><span class=3D"gmail-m_496997=
4058834108480gmail-m_-4498339902504097115gmail-">On Tue, Feb 7, 2017 at 4:5=
2 AM, Arthur O'Dwyer <span dir=3D"ltr"><<a href=3D"mailto:arthur.j.o=
dwyer@gmail.com" target=3D"_blank">arthur.j.odwyer@gmail.com</a>></span>=
wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.=
8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204=
,204,204);padding-left:1ex"><div dir=3D"ltr"><span>On Tue, Jan 31, 2017 at =
8:52 PM, <span dir=3D"ltr"><<a href=3D"mailto:joseph.thomson@gmail.com"=
target=3D"_blank">joseph.thomson@gmail.com</a>></span> wrote:<br></span=
><div class=3D"gmail_extra"><div class=3D"gmail_quote"><span><blockquote cl=
ass=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px=
;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1e=
x"><div dir=3D"ltr">On Wednesday, 1 February 2017 08:23:32 UTC+8, Arthur O&=
#39;Dwyer wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px =
0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:r=
gb(204,204,204);padding-left:1ex"><div dir=3D"ltr">On Tuesday, January 31, =
2017 at 6:26:30 AM UTC-8, <a>joseph....@gmail.com</a> wrote:<blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;=
border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex=
">There is currently no uniform way to retrieve a pointer from an arbitrary=
pointer or pointer-like object. One real example where such a feature woul=
d be useful is the proposed `propagate_const` wrapper, which currently requ=
ires compatible class types to have a `get` member function. This is an int=
rusive requirement, that the user may not even have the capacity to meet.</=
blockquote><div><br></div><div><a href=3D"http://en.cppreference.com/w/cpp/=
experimental/propagate_const/get" rel=3D"nofollow" target=3D"_blank">http:/=
/en.cppreference.com/w/c<wbr>pp/experimental/propagate_cons<wbr>t/get</a><b=
r></div><div><br></div><div>I agree that the current text there seems stupi=
d. It currently says that the return value of t.get() ought to be:</div><di=
v>>=C2=A0<span style=3D"color:rgb(0,0,0);font-family:dejavusans,'dej=
avu sans',arial,sans-serif">If=C2=A0</span><code style=3D"background-co=
lor:transparent;color:rgb(0,0,0);font-family:dejavusansmono,'dejavu san=
s mono',courier,monospace">T</code><span style=3D"color:rgb(0,0,0);font=
-family:dejavusans,'dejavu sans',arial,sans-serif">=C2=A0is an obje=
ct pointer type, then=C2=A0</span><span style=3D"background-color:rgba(0,0,=
0,0.0235294);border:1px solid rgb(214,214,214);border-top-left-radius:3px;b=
order-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-lef=
t-radius:3px;margin-right:2px;margin-left:2px;padding-right:2px;padding-lef=
t:2px;display:inline-block;color:rgb(0,0,0);font-family:dejavusans,'dej=
avu sans',arial,sans-serif"><span style=3D"line-height:normal;white-spa=
ce:nowrap;font-family:dejavusansmono,'dejavu sans mono',courier,mon=
ospace">t_</span></span><span style=3D"color:rgb(0,0,0);font-family:dejavus=
ans,'dejavu sans',arial,sans-serif">. Otherwise,=C2=A0</span><span =
style=3D"background-color:rgba(0,0,0,0.0235294);border:1px solid rgb(214,21=
4,214);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom=
-right-radius:3px;border-bottom-left-radius:3px;margin-right:2px;margin-lef=
t:2px;padding-right:2px;padding-left:2px;display:inline-block;color:rgb(0,0=
,0);font-family:dejavusans,'dejavu sans',arial,sans-serif"><span st=
yle=3D"line-height:normal;white-space:nowrap;font-family:dejavusansmono,=
9;dejavu sans mono',courier,monospace">t_.<span>get</span><span style=
=3D"color:rgb(0,128,0)">(</span><span style=3D"color:rgb(0,128,0)">)</span>=
</span></span><span style=3D"color:rgb(0,0,0);font-family:dejavusans,'d=
ejavu sans',arial,sans-serif">.</span><br></div><div>IMO it would be a =
strict usability improvement to say simply that t.get() returns</div><div>&=
gt; <span style=3D"margin-right:2px;margin-left:2px;padding-right:2px;paddi=
ng-left:2px;border:1px solid rgb(214,214,214);background-color:rgba(0,0,0,0=
..0235294);border-top-left-radius:3px;border-top-right-radius:3px;border-bot=
tom-right-radius:3px;border-bottom-left-radius:3px;display:inline-block;col=
or:rgb(0,0,0);font-family:dejavusans,'dejavu sans',arial,sans-serif=
"><span style=3D"line-height:normal;white-space:nowrap;font-family:dejavusa=
nsmono,'dejavu sans mono',courier,monospace">std::addressof(*t_)</s=
pan></span><span style=3D"color:rgb(0,0,0);font-family:dejavusans,'deja=
vu sans',arial,sans-serif">.</span></div><div><span style=3D"color:rgb(=
0,0,0);font-family:dejavusans,'dejavu sans',arial,sans-serif"><br><=
/span></div><div><span style=3D"color:rgb(0,0,0);font-family:dejavusans,=
9;dejavu sans',arial,sans-serif">Besides being shorter, simpler, and &q=
uot;obviously correct" for non-class types, this would elegantly avoid=
the current problem for class types when </span><span style=3D"color:rgb(0=
,0,0)"><font face=3D"courier new, monospace">decltype(t_.get())</font></spa=
n><span style=3D"color:rgb(0,0,0);font-family:dejavusans,'dejavu sans&#=
39;,arial,sans-serif"> is not convertible to=C2=A0</span><span style=3D"col=
or:rgb(0,0,0)"><font face=3D"courier new, monospace">element_type</font></s=
pan><span style=3D"color:rgb(0,0,0);font-family:dejavusans,'dejavu sans=
',arial,sans-serif">.</span></div></div></blockquote><div>=C2=A0<br>Tha=
t wouldn't work for null pointers.</div></div></blockquote><div><br></d=
iv></span><div>Good point. To work with null pointers, I'd want</div><d=
iv><br></div><div><font face=3D"monospace, monospace">template<typename =
T></font></div><div><font face=3D"monospace, monospace">auto <i>GETPOINT=
ER</i>(T&& t) {</font></div><div><font face=3D"monospace, monospace=
">=C2=A0 =C2=A0 return t ? std::addressof(*t) : nullptr;</font></div><div><=
font face=3D"monospace, monospace">}</font></div></div></div></div></blockq=
uote><div><br></div></span><div>The problem is that not all pointer-like ty=
pes are contextually convertible to <span style=3D"font-family:monospace,mo=
nospace">`bool`</span>.<br></div></div></div></div></blockquote><div><br></=
div></span><div>I'd say either that yes they are; or else that you coul=
d replace <font face=3D"monospace, monospace">t</font> above with <font fac=
e=3D"monospace, monospace">t !=3D nullptr</font> or even <font face=3D"mono=
space, monospace">t !=3D decltype(t){}</font> without loss of sense. I don&=
#39;t have a particular preference among those three options. </div><span c=
lass=3D"gmail-m_4969974058834108480gmail-"></span></div></div></div></block=
quote><div><br></div></span><div>My proposal was motivated by the creation =
of a "not null" pointer type (which I'm either going to propo=
se for inclusion in the standard or the GSL), so I definitely think that it=
's possible for pointer-like types to not be contextually convertible t=
o <span style=3D"font-family:monospace,monospace">`bool`</span> (especially=
if, as you point out, iterators are considered pointer-like).<br></div></d=
iv></div></div></blockquote><div><br></div><div>My kneejerk reaction is tha=
t even a "never null" pointer type ought to be contextually conve=
rtible to bool. Its conversion function might be as simple as</div><div><br=
></div><div>=C2=A0 =C2=A0 constexpr operator bool() const noexcept { return=
true; }</div><div><br></div><div>but it should still exist; otherwise you =
wouldn't be able to test the pointer with "if (p)", which wou=
ld make it unnecessarily awkward to drop into existing codebases.</div><div=
>However, prior art seems to fall on the side of not allowing comparison of=
known-non-null things with null things:</div><div><br></div><div>- <a href=
=3D"https://github.com/dropbox/nn/blob/master/nn.hpp#L96">Dropbox's nn<=
/a> doesn't provide operator bool()</div><div>- <a href=3D"https://gith=
ub.com/Microsoft/GSL/blob/master/include/gsl/gsl#L72">GSL's not_null</a=
> doesn't provide operator bool(), nor even relational operators =3D=3D=
!=3D</div><div>- <a href=3D"https://github.com/martinmoene/gsl-lite/blob/m=
aster/include/gsl/gsl-lite.h#L856">Martin Moene's not_null</a> doesn=
9;t provide operator bool()<br></div><div><br></div><div>Now, we could stil=
l do something like</div><div><br></div><div><font face=3D"monospace, monos=
pace">=C2=A0 =C2=A0 template<typename T></font></div><div><font face=
=3D"monospace, monospace">=C2=A0 =C2=A0 auto GETPOINTER(T&& t) {</f=
ont></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 if constexpr(is_convertible_v<T&&, bool>) {</font></div><=
div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 return bool(t) ?=C2=A0</font><span style=3D"font-family:monospace,mo=
nospace">std::addressof(*t) : nullptr;</span></div><div><span style=3D"font=
-family:monospace,monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 }</span><br></div>=
<div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 return=
std::addressof(*t);</font></div><div><font face=3D"monospace, monospace">=
=C2=A0 =C2=A0 }</font></div><div><br></div><div>Question, mostly whimsical:=
What would you expect to happen if I provided an AlwaysNull<T> type =
that was the complementary type to NotNull<T>?=C2=A0 That is,</div><d=
iv><br></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 int i =
=3D 42;</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =
AlwaysNull<int *> an =3D nullptr; // ok</font></div><div><font face=
=3D"monospace, monospace">=C2=A0 =C2=A0 AlwaysNull<int *> an2 =3D &am=
p;i; =C2=A0// runtime error</font></div><div><font face=3D"monospace, monos=
pace">=C2=A0 =C2=A0 if (an) { ... } =C2=A0// compile-time error: AlwaysNull=
<int *> is not convertible to bool because "<a href=3D"https://g=
ithub.com/dropbox/nn/blob/master/nn.hpp#L93">that would be silly</a>"<=
/font></div><div><br></div><div>If this happened, would you want <font face=
=3D"monospace, monospace">GETPOINTER(an)</font> to "do the right thing=
" and return nullptr, or would you want it to have undefined behavior,=
or what?</div><div><br></div><div><br></div><blockquote class=3D"gmail_quo=
te" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-col=
or:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir=3D"l=
tr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><span class=3D"gm=
ail-"><div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px =
0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-col=
or:rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_=
extra"><div class=3D"gmail_quote"><div></div><div>Now, there is still a pro=
blem, even in my happy world where all "pointer-like" types imple=
ment <font face=3D"monospace, monospace">operator*</font>. The problem is t=
hat sometimes a pointer can be non-null and <i>still</i> not point to an ob=
ject. For example:</div><div><br></div><div><font face=3D"monospace, monosp=
ace">=C2=A0 =C2=A0 std::vector<int> a(42);</font></div><div><font fac=
e=3D"monospace, monospace">=C2=A0 =C2=A0 int *p =3D &a[0] + 42;<br></fo=
nt></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 assert(p !=
=3D decltype(p){});</font></div><div><font face=3D"monospace, monospace">=
=C2=A0 =C2=A0 // Nevertheless we are not allowed to call std::addressof(*p)=
as far as I know</font></div><div><font face=3D"monospace, monospace"><br>=
</font></div><div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 au=
to it =3D a.end();<br></font></div><div><font face=3D"monospace, monospace"=
>=C2=A0 =C2=A0 assert(it !=3D decltype(it){});</font></div><div><font face=
=3D"monospace, monospace">=C2=A0 =C2=A0 // Nevertheless we are not allowed =
to call std::addressof(*it)<br></font></div></div><div><br></div><div>What =
behavior would you want for <font face=3D"monospace, monospace">std::get_po=
inter(p)</font>=C2=A0(respectiv<wbr>ely=C2=A0<font face=3D"monospace, monos=
pace">std::get_pointer(it)</font>) in this case?</div><div>I suspect you=
9;d want <font face=3D"monospace, monospace">std::get_pointer(p) =3D=3D p</=
font> somehow. I hope you're <i>not</i> going to claim that <font face=
=3D"monospace, monospace">decltype(it)</font> is "not a pointer-like t=
ype"; but I'm not sure it's implementable to mandate that <fon=
t face=3D"monospace, monospace">std::get_pointer(it)</font>=C2=A0consisten<=
wbr>tly return either=C2=A0<font face=3D"monospace, monospace">nullptr</fon=
t> or <font face=3D"monospace, monospace">p</font>.</div></div></div></div>=
</blockquote><div><br></div></span><div>I had to think about this for a whi=
le. I think post-C++17, once contiguous iterators are a thing, both <span s=
tyle=3D"font-family:monospace,monospace">`get_pointer(a.data() + a.size())`=
</span> and <span style=3D"font-family:monospace,monospace">`get_pointer(a.=
end())`</span> would return <span style=3D"font-family:monospace,monospace"=
>`a.data() + a.size()`</span>. For non-contiguous iterators, a past-the-end=
iterator is not guaranteed to point to a memory address, so the behaviour =
of <span style=3D"font-family:monospace,monospace">`get_pointer(a.end())`</=
span> would be undefined. As you point out, <span style=3D"font-family:mono=
space,monospace">`&*p`</span> gives undefined behaviour for past-the-en=
d iterators, so we need some other method to extract the pointer. I suggest=
explicit conversion to <span style=3D"font-family:monospace,monospace">`T*=
`</span>. The contiguous iterator proposal noted that they considered this,=
but some were worried that this would <i>"[go] too far towards weake=
ning the boundary between pointers and iterators"</i>. I think this co=
ncern is misplaced.<br></div></div></div></div></blockquote><div><br></div>=
<div>I don't see any reason to define the behavior of <font face=3D"mon=
ospace, monospace">GETPOINTER(a.end())</font> given that there flatly <i>is=
no object</i> at any memory address that could reasonably be associated wi=
th <font face=3D"monospace, monospace">a.end()</font>. If I understand corr=
ectly, we're in agreement that <font face=3D"monospace, monospace">GETP=
OINTER(a.end())</font> should be undefined for e.g. <font face=3D"monospace=
, monospace">std::list<int> a</font>; we're only in disagreement =
about whether it should be defined for std::vector and std::array.</div><di=
v><br></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"mar=
gin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,2=
04);border-left-style:solid;padding-left:1ex"><div dir=3D"ltr"><div class=
=3D"gmail_extra"><div class=3D"gmail_quote"><div><br></div><span class=3D"g=
mail-"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;=
border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204=
,204);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><div cl=
ass=3D"gmail_quote"><div>By the way, does your intuition agree with mine th=
at <b><font face=3D"monospace, monospace">std::exception_ptr</font> is not =
a "pointer-like type"</b>? =C2=A0(It does model <font face=3D"mon=
ospace, monospace">NullablePointer</font>, but it is not dereferenceable an=
d doesn't "point to" anything in a meaningful sense.)</div><d=
iv>Alternatively, if you think it <i>is</i> a pointer-like type, what shoul=
d be returned by <font face=3D"monospace, monospace">std::get_pointer(std::=
current_<wbr>exception())</font>?</div></div></div></div></blockquote><div>=
<br></div></span><div>Yes, I agree that <span style=3D"font-family:monospac=
e,monospace">`exception_ptr`</span> is not a pointer-like type, though &quo=
t;pointer-like" is not a concept defined by the standard. If I were go=
ing to standardize a <span style=3D"font-family:monospace,monospace">Pointe=
rLike</span> concept, I would probably do something like this: an object <s=
pan style=3D"font-family:monospace,monospace">`p`</span> (and object <span =
style=3D"font-family:monospace,monospace">`q`</span> of the same type) is o=
f <span style=3D"font-family:monospace,monospace">PointerLike</span> type i=
f for some type <span style=3D"font-family:monospace,monospace">`T`</span>:=
<br></div><div><ul><li><span style=3D"font-family:monospace,monospace">`sta=
tic_cast<T*>(p)`</span> is a valid expression<br><span style=3D"font-=
family:monospace,monospace"></span></li><li><span style=3D"font-family:mono=
space,monospace">`*p`</span> is equivalent to <span style=3D"font-family:mo=
nospace,monospace">`*static_cast<T*>(p)`</span></li><li><span style=
=3D"font-family:monospace,monospace">`p.operator->()`</span><span style=
=3D"font-family:arial,helvetica,sans-serif"> is equivalent to </span><span =
style=3D"font-family:monospace,monospace">`static_cast<T*>(p)`<br></s=
pan></li><li><span style=3D"font-family:monospace,monospace">`p =3D=3D q`</=
span> is equivalent to <span style=3D"font-family:monospace,monospace"><spa=
n style=3D"font-family:monospace,monospace">`static_cast<T*>(</span>p=
) =3D=3D </span><span style=3D"font-family:monospace,monospace"><span style=
=3D"font-family:monospace,monospace">static_cast<T*>(</span>q)`</span=
></li><li><span style=3D"font-family:monospace,monospace">`p !=3D q`</span>=
is equivalent to <span style=3D"font-family:monospace,monospace">`!(p =3D=
=3D q)`</span></li></ul></div></div></div></div></blockquote><div>I would s=
ay simply</div><div><br></div><div><font face=3D"monospace, monospace">temp=
late<typename T></font></div><div><font face=3D"monospace, monospace"=
>concept bool PointerLike() {</font></div><div><font face=3D"monospace, mon=
ospace">=C2=A0 =C2=A0 return requires(T p) {</font></div><div><font face=3D=
"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 { *p };</font></div><div=
><font face=3D"monospace, monospace">=C2=A0 =C2=A0 };<br></font></div><div>=
<font face=3D"monospace, monospace">}</font></div><div><font face=3D"monosp=
ace, monospace"><br></font></div><div><div><font face=3D"monospace, monospa=
ce">template<typename T></font></div><div><font face=3D"monospace, mo=
nospace">concept bool NullablePointerLike() {</font></div><div><font face=
=3D"monospace, monospace">=C2=A0 =C2=A0 return PointerLike<T>() &=
& requires(T p) {</font></div><div><font face=3D"monospace, monospace">=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 { p } -> bool;</font></div><div><font face=
=3D"monospace, monospace">=C2=A0 =C2=A0 };</font></div><div><font face=3D"m=
onospace, monospace">}<br></font></div></div><div><br></div><div>I definite=
ly would not expect <font face=3D"monospace, monospace">static_cast<T*&g=
t;(p)</font> to work; for example it doesn't work for <a href=3D"http:/=
/en.cppreference.com/w/cpp/memory/shared_ptr">std::shared_ptr</a> or <a hre=
f=3D"http://en.cppreference.com/w/cpp/memory/unique_ptr">std::unique_ptr</a=
>, which IMNSHO certainly ought to be considered "pointer-like types&q=
uot;.</div><div><br></div><div>More weakly, I wouldn't necessarily expe=
ct <font face=3D"monospace, monospace">p =3D=3D q</font> or <font face=3D"m=
onospace, monospace">p !=3D q</font> to work. There are some algorithms tha=
t might require both PointerLike and EqualityComparable, but I can think of=
many algorithms (e.g. <font face=3D"monospace, monospace">iter_swap</font>=
) that require PointerLike <i>without</i> EqualityComparable.=C2=A0 That sa=
id, I can't off the top of my head think of any "pointer-like"=
; types that don't support the relational operators except for <a href=
=3D"https://github.com/Microsoft/GSL/blob/master/include/gsl/gsl#L72">the G=
SL's <font face=3D"monospace, monospace">nn<int*></font></a> (and=
I can only imagine that that was a horrific oversight).</div><div><br></di=
v><div>Here is a table of the operations we've been discussing, and the=
ir well-formedness for a bunch of relevant types, listed roughly from most =
to least "pointer-like" IMHO. Feel free to extend it with more ro=
ws and/or columns!</div><div><br></div><div><span style=3D"font-family:mono=
space,monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 A B C D E F</span></div><div><spa=
n style=3D"font-family:monospace,monospace">int* =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Y Y Y Y . Y</spa=
n><br></div><div><font face=3D"monospace, monospace">shared_ptr<int> =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Y . Y Y Y Y</font></div><div><fon=
t face=3D"monospace, monospace">unique_ptr<int> =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 Y . Y Y Y Y</font></div><div><font face=3D"monospace, =
monospace">Dropbox nn<int*> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
.. Y Y Y . Y</font></div><div><font face=3D"monospace, monospace">Dropbox nn=
<shared_ptr<int>> . . Y Y Y Y</font></div><div><span style=3D"f=
ont-family:monospace,monospace">gsl::not_null<int*> =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 . Y . Y Y .</span><br></div><div><span style=3D"font-family:mono=
space,monospace">std::vector<int>::iterator =C2=A0. . . Y . Y</span><=
br></div><div><span style=3D"font-family:monospace,monospace">std::list<=
int>::iterator =C2=A0 =C2=A0. . . Y . Y</span></div><div><div><span styl=
e=3D"font-family:monospace,monospace">istream_iterator<int> =C2=A0 =
=C2=A0 =C2=A0 . . . Y . Y</span><br></div><div><span style=3D"font-family:m=
onospace,monospace">ostream_iterator<int> =C2=A0 =C2=A0 =C2=A0 . . . =
Y . .</span></div><div><span style=3D"font-family:monospace,monospace">std:=
:nullptr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Y Y Y . . Y</spa=
n><br></div><div><font face=3D"monospace, monospace">void* =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Y Y Y . . Y<=
/font></div><div><span style=3D"font-family:monospace,monospace">std::excep=
tion_ptr =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Y . Y . . Y</span></div><div><sp=
an style=3D"font-family:monospace,monospace">std::optional<int> =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Y . . Y . Y</span></div><div><span style=3D"=
font-family:monospace,monospace">std::future<int> =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0. . . . Y .</span></div><div><span style=3D"font-fa=
mily:monospace,monospace">std::reference_wrapper<int> . . . . Y Y</sp=
an></div><div><br></div><div><span style=3D"font-family:monospace,monospace=
">A: static_cast<bool>(p)</span></div></div><div><div><span style=3D"=
font-family:monospace,monospace">B: static_cast<int*>(p)</span></div>=
<div><span style=3D"font-family:monospace,monospace">C: p =3D=3D nullptr</s=
pan></div><div><span style=3D"font-family:monospace,monospace">D: *p</span>=
</div><div><span style=3D"font-family:monospace,monospace">E: p.get()</span=
></div></div><div><span style=3D"font-family:monospace,monospace">F: p =3D=
=3D q</span></div><div><span style=3D"font-family:monospace,monospace"><br>=
</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/CADvuK0LwSa2kEj1e-RPcw8%3DPFHjs7JXMJZ=
-twygGZKg0W4jJrA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0LwSa2kEj=
1e-RPcw8%3DPFHjs7JXMJZ-twygGZKg0W4jJrA%40mail.gmail.com</a>.<br />
--f403045f1e92b6756d05488d40e2--
.
Author: Joseph Thomson <joseph.thomson@gmail.com>
Date: Wed, 15 Feb 2017 21:49:01 +0800
Raw View
--001a1145b3f076494e054891f168
Content-Type: text/plain; charset=UTF-8
On Wed, Feb 15, 2017 at 4:13 PM, Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
wrote:
> My kneejerk reaction is that even a "never null" pointer type ought to be
> contextually convertible to bool. Its conversion function might be as
> simple as
>
> constexpr operator bool() const noexcept { return true; }
>
> but it should still exist; otherwise you wouldn't be able to test the
> pointer with "if (p)", which would make it unnecessarily awkward to drop
> into existing codebases.
> However, prior art seems to fall on the side of not allowing comparison of
> known-non-null things with null things:
>
> - Dropbox's nn <https://github.com/dropbox/nn/blob/master/nn.hpp#L96>
> doesn't provide operator bool()
> - GSL's not_null
> <https://github.com/Microsoft/GSL/blob/master/include/gsl/gsl#L72>
> doesn't provide operator bool(), nor even relational operators == !=
> - Martin Moene's not_null
> <https://github.com/martinmoene/gsl-lite/blob/master/include/gsl/gsl-lite.h#L856>
> doesn't provide operator bool()
>
I initially thought so too, but I think it is good design to only include
features that have a purpose. Omitting conversion to `bool` may actually
simplify user code by causing removal of pointless conditional statements.
> Now, we could still do something like
>
> template<typename T>
> auto GETPOINTER(T&& t) {
> if constexpr(is_convertible_v<T&&, bool>) {
> return bool(t) ? std::addressof(*t) : nullptr;
> }
> return std::addressof(*t);
> }
>
That would only work if the behaviour of `GETPOINTER(p)` were undefined for
contiguous past-the-end iterators (and I think it should be defined).
Question, mostly whimsical: What would you expect to happen if I provided
> an AlwaysNull<T> type that was the complementary type to NotNull<T>? That
> is,
>
> int i = 42;
> AlwaysNull<int *> an = nullptr; // ok
> AlwaysNull<int *> an2 = &i; // runtime error
> if (an) { ... } // compile-time error: AlwaysNull<int *> is not
> convertible to bool because "that would be silly
> <https://github.com/dropbox/nn/blob/master/nn.hpp#L93>"
>
> If this happened, would you want GETPOINTER(an) to "do the right thing"
> and return nullptr, or would you want it to have undefined behavior, or
> what?
>
It should return a null pointer. It's a bit of a pointless type though.
>> Now, there is still a problem, even in my happy world where all
>>> "pointer-like" types implement operator*. The problem is that sometimes
>>> a pointer can be non-null and *still* not point to an object. For
>>> example:
>>>
>>> std::vector<int> a(42);
>>> int *p = &a[0] + 42;
>>> assert(p != decltype(p){});
>>> // Nevertheless we are not allowed to call std::addressof(*p) as far
>>> as I know
>>>
>>> auto it = a.end();
>>> assert(it != decltype(it){});
>>> // Nevertheless we are not allowed to call std::addressof(*it)
>>>
>>> What behavior would you want for std::get_pointer(p) (respectively
>>> std::get_pointer(it)) in this case?
>>> I suspect you'd want std::get_pointer(p) == p somehow. I hope you're
>>> *not* going to claim that decltype(it) is "not a pointer-like type";
>>> but I'm not sure it's implementable to mandate that std::get_pointer(it)
>>> consistently return either nullptr or p.
>>>
>>
>> I had to think about this for a while. I think post-C++17, once
>> contiguous iterators are a thing, both `get_pointer(a.data() + a.size())`
>> and `get_pointer(a.end())` would return `a.data() + a.size()`. For
>> non-contiguous iterators, a past-the-end iterator is not guaranteed to
>> point to a memory address, so the behaviour of `get_pointer(a.end())`
>> would be undefined. As you point out, `&*p` gives undefined behaviour
>> for past-the-end iterators, so we need some other method to extract the
>> pointer. I suggest explicit conversion to `T*`. The contiguous iterator
>> proposal noted that they considered this, but some were worried that this
>> would *"[go] too far towards weakening the boundary between pointers and
>> iterators"*. I think this concern is misplaced.
>>
>
> I don't see any reason to define the behavior of GETPOINTER(a.end())
> given that there flatly *is no object* at any memory address that could
> reasonably be associated with a.end(). If I understand correctly, we're
> in agreement that GETPOINTER(a.end()) should be undefined for e.g. std::list<int>
> a; we're only in disagreement about whether it should be defined for
> std::vector and std::array.
>
Pointers do not have to point to valid objects. It makes sense that *all*
contiguous iterators map to a valid pointer because this mapping is well
defined. Making an exception for past-the-end iterators would complicate
things enormously. Consider how one might implement GSL's `span` type:
T* b_ptr;
T* e_ptr;
template <typename ContiguousIterator>
span(ContiguousIterator b, ContiguousIterator e) :
b_ptr(get_pointer(b)),
e_ptr(get_pointer(e))
{
}
If `get_pointer` works with past-the-end iterators, then all is fine. If
not, then you can't be sure if `b` or `e` can be used with `get_pointer`,
and you'd have to do something crazy like this:
b_ptr(b != e ? get_pointer(b) : nullptr),
e_ptr(b != e ? get_pointer(b) + (e - b - 1) : nullptr)
But then there isn't really any advantage in using `get_pointer` at all:
b_ptr(b != e ? &*b : nullptr),
e_ptr(b != e ? &*b + (e - b - 1) : nullptr)
If I were going to standardize a PointerLike concept, I would probably do
>> something like this: an object `p` (and object `q` of the same type) is
>> of PointerLike type if for some type `T`:
>>
>> - `static_cast<T*>(p)` is a valid expression
>> - `*p` is equivalent to `*static_cast<T*>(p)`
>> - `p.operator->()` is equivalent to `static_cast<T*>(p)`
>> - `p == q` is equivalent to `static_cast<T*>(p) == static_cast<T*>(q)`
>> - `p != q` is equivalent to `!(p == q)`
>>
>> I would say simply
>
> template<typename T>
> concept bool PointerLike() {
> return requires(T p) {
> { *p };
> };
> }
>
> template<typename T>
> concept bool NullablePointerLike() {
> return PointerLike<T>() && requires(T p) {
> { p } -> bool;
> };
> }
>
Not all types that define the indirection operators are pointer-like, for
example, `optional<T>`. That's why I include the requirement that
comparison be equivalent to comparing the underlying pointers (i.e.
reference semantics). There needs to be some way to distinguish value types
that implement `*` and `->` from pointer-like types.
> I definitely would not expect static_cast<T*>(p) to work; for example it
> doesn't work for std::shared_ptr
> <http://en.cppreference.com/w/cpp/memory/shared_ptr> or std::unique_ptr
> <http://en.cppreference.com/w/cpp/memory/unique_ptr>, which IMNSHO
> certainly ought to be considered "pointer-like types".
>
Explicit conversion to `T*` would be added for these types, and any other
types that want to meet the requirements for PointerLike.
More weakly, I wouldn't necessarily expect p == q or p != q to work. There
> are some algorithms that might require both PointerLike and
> EqualityComparable, but I can think of many algorithms (e.g. iter_swap)
> that require PointerLike *without* EqualityComparable. That said, I
> can't off the top of my head think of any "pointer-like" types that don't
> support the relational operators except for the GSL's nn<int*>
> <https://github.com/Microsoft/GSL/blob/master/include/gsl/gsl#L72> (and I
> can only imagine that that was a horrific oversight).
>
I'm not sure whether PointerLike needs to require relational operators, but
if they are defined, they must have reference semantics. I don't really see
this requirement being much of an issue though.
And `not_null<T*>` implicitly converts to `T*`, so it does support
comparison, among other things.
--
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/CAHocnE_-dK5A4cD6WGWGoSD51zY5DhTbej34OVELRsPgUXQufA%40mail.gmail.com.
--001a1145b3f076494e054891f168
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On W=
ed, Feb 15, 2017 at 4:13 PM, Arthur O'Dwyer <span dir=3D"ltr"><<a hr=
ef=3D"mailto:arthur.j.odwyer@gmail.com" target=3D"_blank">arthur.j.odwyer@g=
mail.com</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding=
-left:1ex"><div dir=3D"ltr"><span class=3D"gmail-"></span><div class=3D"gma=
il_quote"><span class=3D"gmail-"></span><div>My kneejerk reaction is that e=
ven a "never null" pointer type ought to be contextually converti=
ble to bool. Its conversion function might be as simple as</div><div><br></=
div><div>=C2=A0 =C2=A0 constexpr operator bool() const noexcept { return tr=
ue; }</div><div><br></div><div>but it should still exist; otherwise you wou=
ldn't be able to test the pointer with "if (p)", which would =
make it unnecessarily awkward to drop into existing codebases.</div><div>Ho=
wever, prior art seems to fall on the side of not allowing comparison of kn=
own-non-null things with null things:</div><div><br></div><div>- <a href=3D=
"https://github.com/dropbox/nn/blob/master/nn.hpp#L96" target=3D"_blank">Dr=
opbox's nn</a> doesn't provide operator bool()</div><div>- <a href=
=3D"https://github.com/Microsoft/GSL/blob/master/include/gsl/gsl#L72" targe=
t=3D"_blank">GSL's not_null</a> doesn't provide operator bool(), no=
r even relational operators =3D=3D !=3D</div><div>- <a href=3D"https://gith=
ub.com/martinmoene/gsl-lite/blob/master/include/gsl/gsl-lite.h#L856" target=
=3D"_blank">Martin Moene's not_null</a> doesn't provide operator bo=
ol()<br></div></div></div></blockquote><div><br></div><div>I initially thou=
ght so too, but I think it is good design to only include features that hav=
e a purpose. Omitting conversion to `bool` may actually simplify user code =
by causing removal of pointless conditional statements.<br></div><div>=C2=
=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8e=
x;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"=
><div class=3D"gmail_quote"><div>Now, we could still do something like</div=
><span class=3D"gmail-"><div><br></div><div><font face=3D"monospace, monosp=
ace">=C2=A0 =C2=A0 template<typename T></font></div><div><font face=
=3D"monospace, monospace">=C2=A0 =C2=A0 auto GETPOINTER(T&& t) {</f=
ont></div></span><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 if constexpr(is_convertible_v<T&&<wbr>, bool>) {</=
font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 return bool(t) ?=C2=A0</font><span style=3D"font-famil=
y:monospace,monospace">std::addressof(*t) : nullptr;</span></div><div><span=
style=3D"font-family:monospace,monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 }</s=
pan><br></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0=
=C2=A0 return std::addressof(*t);</font></div><div><font face=3D"monospace=
, monospace">=C2=A0 =C2=A0 }</font></div></div></div></blockquote><div>=C2=
=A0<br></div><div>That would only work if the behaviour of `GETPOINTER(p)` =
were undefined for contiguous past-the-end iterators (and I think it should=
be defined).<br></div><div><br></div><blockquote class=3D"gmail_quote" sty=
le=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);paddi=
ng-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_quote"><div></div><div>Qu=
estion, mostly whimsical: What would you expect to happen if I provided an =
AlwaysNull<T> type that was the complementary type to NotNull<T>=
;?=C2=A0 That is,</div><div><br></div><div><font face=3D"monospace, monospa=
ce">=C2=A0 =C2=A0 int i =3D 42;</font></div><div><font face=3D"monospace, m=
onospace">=C2=A0 =C2=A0 AlwaysNull<int *> an =3D nullptr; // ok</font=
></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 AlwaysNull<=
;int *> an2 =3D &i; =C2=A0// runtime error</font></div><div><font fa=
ce=3D"monospace, monospace">=C2=A0 =C2=A0 if (an) { ... } =C2=A0// compile-=
time error: AlwaysNull<int *> is not convertible to bool because &quo=
t;<a href=3D"https://github.com/dropbox/nn/blob/master/nn.hpp#L93" target=
=3D"_blank">that would be silly</a>"</font></div><div><br></div><div>I=
f this happened, would you want <font face=3D"monospace, monospace">GETPOIN=
TER(an)</font> to "do the right thing" and return nullptr, or wou=
ld you want it to have undefined behavior, or what?</div><span class=3D"gma=
il-"></span></div></div></blockquote><div><br></div><div>It should return a=
null pointer. It's a bit of a pointless type though.<br></div><div><br=
></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;=
border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><=
div class=3D"gmail_quote"><span class=3D"gmail-"><blockquote class=3D"gmail=
_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204=
,204);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><div cl=
ass=3D"gmail_quote"><span class=3D"gmail-m_428563140955204213gmail-"><div><=
br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8e=
x;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"=
><div class=3D"gmail_extra"><div class=3D"gmail_quote"><div>Now, there is s=
till a problem, even in my happy world where all "pointer-like" t=
ypes implement <font face=3D"monospace, monospace">operator*</font>. The pr=
oblem is that sometimes a pointer can be non-null and <i>still</i> not poin=
t to an object. For example:</div><div><br></div><div><font face=3D"monospa=
ce, monospace">=C2=A0 =C2=A0 std::vector<int> a(42);</font></div><div=
><font face=3D"monospace, monospace">=C2=A0 =C2=A0 int *p =3D &a[0] + 4=
2;<br></font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 a=
ssert(p !=3D decltype(p){});</font></div><div><font face=3D"monospace, mono=
space">=C2=A0 =C2=A0 // Nevertheless we are not allowed to call std::addres=
sof(*p) as far as I know</font></div><div><font face=3D"monospace, monospac=
e"><br></font></div><div><div><font face=3D"monospace, monospace">=C2=A0 =
=C2=A0 auto it =3D a.end();<br></font></div><div><font face=3D"monospace, m=
onospace">=C2=A0 =C2=A0 assert(it !=3D decltype(it){});</font></div><div><f=
ont face=3D"monospace, monospace">=C2=A0 =C2=A0 // Nevertheless we are not =
allowed to call std::addressof(*it)<br></font></div></div><div><br></div><d=
iv>What behavior would you want for <font face=3D"monospace, monospace">std=
::get_pointer(p)</font>=C2=A0(respectiv<wbr>ely=C2=A0<font face=3D"monospac=
e, monospace">std::get_pointer(it)</font>) in this case?</div><div>I suspec=
t you'd want <font face=3D"monospace, monospace">std::get_pointer(p) =
=3D=3D p</font> somehow. I hope you're <i>not</i> going to claim that <=
font face=3D"monospace, monospace">decltype(it)</font> is "not a point=
er-like type"; but I'm not sure it's implementable to mandate =
that <font face=3D"monospace, monospace">std::get_pointer(it)</font>=C2=A0c=
onsisten<wbr>tly return either=C2=A0<font face=3D"monospace, monospace">nul=
lptr</font> or <font face=3D"monospace, monospace">p</font>.</div></div></d=
iv></div></blockquote><div><br></div></span><div>I had to think about this =
for a while. I think post-C++17, once contiguous iterators are a thing, bot=
h <span style=3D"font-family:monospace,monospace">`get_pointer(a.data() + a=
..size())`</span> and <span style=3D"font-family:monospace,monospace">`get_p=
ointer(a.end())`</span> would return <span style=3D"font-family:monospace,m=
onospace">`a.data() + a.size()`</span>. For non-contiguous iterators, a pas=
t-the-end iterator is not guaranteed to point to a memory address, so the b=
ehaviour of <span style=3D"font-family:monospace,monospace">`get_pointer(a.=
end())`</span> would be undefined. As you point out, <span style=3D"font-fa=
mily:monospace,monospace">`&*p`</span> gives undefined behaviour for pa=
st-the-end iterators, so we need some other method to extract the pointer. =
I suggest explicit conversion to <span style=3D"font-family:monospace,monos=
pace">`T*`</span>. The contiguous iterator proposal noted that they conside=
red this, but some were worried that this would <i>"[go] too far towa=
rds weakening the boundary between pointers and iterators"</i>. I thin=
k this concern is misplaced.<br></div></div></div></div></blockquote><div><=
br></div></span><div>I don't see any reason to define the behavior of <=
font face=3D"monospace, monospace">GETPOINTER(a.end())</font> given that th=
ere flatly <i>is no object</i> at any memory address that could reasonably =
be associated with <font face=3D"monospace, monospace">a.end()</font>. If I=
understand correctly, we're in agreement that <font face=3D"monospace,=
monospace">GETPOINTER(a.end())</font> should be undefined for e.g. <font f=
ace=3D"monospace, monospace">std::list<int> a</font>; we're only =
in disagreement about whether it should be defined for std::vector and std:=
:array.</div></div></div></blockquote><div><br></div><div>Pointers do not h=
ave to point to valid objects. It makes sense that <i>all</i> contiguous it=
erators map to a valid pointer because this mapping is well defined. Making=
an exception for past-the-end iterators would complicate things enormously=
.. Consider how one might implement GSL's `span` type:<br></div><div><br=
></div><div style=3D"margin-left:40px"><span style=3D"font-family:monospace=
,monospace">T* b_ptr;<br></span></div><div style=3D"margin-left:40px"><span=
style=3D"font-family:monospace,monospace">T* e</span><span style=3D"font-f=
amily:monospace,monospace"><span style=3D"font-family:monospace,monospace">=
_ptr</span>;<br><br></span></div><div style=3D"margin-left:40px"><span styl=
e=3D"font-family:monospace,monospace">template <typename ContiguousItera=
tor><br></span></div><div style=3D"margin-left:40px"><span style=3D"font=
-family:monospace,monospace">span(ContiguousIterator b, ContiguousIterator =
e) :<br></span></div><div style=3D"margin-left:40px"><span style=3D"font-fa=
mily:monospace,monospace">=C2=A0=C2=A0=C2=A0 b</span><span style=3D"font-fa=
mily:monospace,monospace"><span style=3D"font-family:monospace,monospace">_=
ptr</span>(get_pointer(b)),<br>=C2=A0=C2=A0=C2=A0 e</span><span style=3D"fo=
nt-family:monospace,monospace"><span style=3D"font-family:monospace,monospa=
ce">_ptr</span>(get_pointer(e))<br></span></div><div style=3D"margin-left:4=
0px"><span style=3D"font-family:monospace,monospace">{<br>}</span><br><span=
style=3D"font-family:monospace,monospace"></span></div><div><br></div><div=
>If `get_pointer` works with past-the-end iterators, then all is fine. If n=
ot, then you can't be sure if `b` or `e` can be used with `get_pointer`=
, and you'd have to do something crazy like this:<br></div><div><br><di=
v style=3D"margin-left:40px"><span style=3D"font-family:monospace,monospace=
">=C2=A0=C2=A0=C2=A0 b</span><span style=3D"font-family:monospace,monospace=
"><span style=3D"font-family:monospace,monospace">_ptr</span>(b !=3D e ? ge=
t_pointer(b) : nullptr),<br>=C2=A0=C2=A0=C2=A0 e</span><span style=3D"font-=
family:monospace,monospace"><span style=3D"font-family:monospace,monospace"=
>_ptr</span>(b !=3D e ? get_pointer(b) + (e - b - 1) : nullptr)<br></span><=
/div><span style=3D"font-family:monospace,monospace"></span><br></div><div>=
But then there isn't really any advantage in using `get_pointer` at all=
:<br><br><div style=3D"margin-left:40px"><span style=3D"font-family:monospa=
ce,monospace">=C2=A0=C2=A0=C2=A0 b</span><span style=3D"font-family:monospa=
ce,monospace"><span style=3D"font-family:monospace,monospace">_ptr</span>(b=
!=3D e ? &*b : nullptr),<br>=C2=A0=C2=A0=C2=A0 e</span><span style=3D"=
font-family:monospace,monospace"><span style=3D"font-family:monospace,monos=
pace">_ptr</span>(b !=3D e ? &*b + (e - b - 1) : nullptr)<br></span></d=
iv><span style=3D"font-family:monospace,monospace"></span></div><div><br></=
div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bor=
der-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div=
class=3D"gmail_quote"><span class=3D"gmail-"><blockquote class=3D"gmail_qu=
ote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,20=
4);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><span clas=
s=3D"gmail-m_428563140955204213gmail-"></span><div class=3D"gmail_quote"><d=
iv>If I were going to standardize a <span style=3D"font-family:monospace,mo=
nospace">PointerLike</span> concept, I would probably do something like thi=
s: an object <span style=3D"font-family:monospace,monospace">`p`</span> (an=
d object <span style=3D"font-family:monospace,monospace">`q`</span> of the =
same type) is of <span style=3D"font-family:monospace,monospace">PointerLik=
e</span> type if for some type <span style=3D"font-family:monospace,monospa=
ce">`T`</span>:<br></div><div><ul><li><span style=3D"font-family:monospace,=
monospace">`static_cast<T*>(p)`</span> is a valid expression<br><span=
style=3D"font-family:monospace,monospace"></span></li><li><span style=3D"f=
ont-family:monospace,monospace">`*p`</span> is equivalent to <span style=3D=
"font-family:monospace,monospace">`*static_cast<T*>(p)`</span></li><l=
i><span style=3D"font-family:monospace,monospace">`p.operator->()`</span=
><span style=3D"font-family:arial,helvetica,sans-serif"> is equivalent to <=
/span><span style=3D"font-family:monospace,monospace">`static_cast<T*>=
;(p)`<br></span></li><li><span style=3D"font-family:monospace,monospace">`p=
=3D=3D q`</span> is equivalent to <span style=3D"font-family:monospace,mon=
ospace"><span style=3D"font-family:monospace,monospace">`static_cast<T*&=
gt;(</span>p) =3D=3D </span><span style=3D"font-family:monospace,monospace"=
><span style=3D"font-family:monospace,monospace">static_cast<T*>(</sp=
an>q)`</span></li><li><span style=3D"font-family:monospace,monospace">`p !=
=3D q`</span> is equivalent to <span style=3D"font-family:monospace,monospa=
ce">`!(p =3D=3D q)`</span></li></ul></div></div></div></div></blockquote></=
span><div>I would say simply</div><div><br></div><div><font face=3D"monospa=
ce, monospace">template<typename T></font></div><div><font face=3D"mo=
nospace, monospace">concept bool PointerLike() {</font></div><div><font fac=
e=3D"monospace, monospace">=C2=A0 =C2=A0 return requires(T p) {</font></div=
><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 { *p =
};</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 };<br=
></font></div><div><font face=3D"monospace, monospace">}</font></div><div><=
font face=3D"monospace, monospace"><br></font></div><div><div><font face=3D=
"monospace, monospace">template<typename T></font></div><div><font fa=
ce=3D"monospace, monospace">concept bool NullablePointerLike() {</font></di=
v><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 return PointerLike=
<T>() && requires(T p) {</font></div><div><font face=3D"monos=
pace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 { p } -> bool;</font></div>=
<div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 };</font></div><div>=
<font face=3D"monospace, monospace">}<br></font></div></div></div></div></b=
lockquote><div><br></div><div>Not all types that define the indirection ope=
rators are pointer-like, for example, `optional<T>`. That's why I=
include the requirement that comparison be equivalent to comparing the und=
erlying pointers (i.e. reference semantics). There needs to be some way to =
distinguish value types that implement `*` and `->` from pointer-like ty=
pes.<br></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"m=
argin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left=
:1ex"><div dir=3D"ltr"><div class=3D"gmail_quote"><div></div><div>I definit=
ely would not expect <font face=3D"monospace, monospace">static_cast<T*&=
gt;(p)</font> to work; for example it doesn't work for <a href=3D"http:=
//en.cppreference.com/w/cpp/memory/shared_ptr" target=3D"_blank">std::share=
d_ptr</a> or <a href=3D"http://en.cppreference.com/w/cpp/memory/unique_ptr"=
target=3D"_blank">std::unique_ptr</a>, which IMNSHO certainly ought to be =
considered "pointer-like types".</div></div></div></blockquote><d=
iv>=C2=A0<br></div><div>Explicit conversion to `T*` would be added for thes=
e types, and any other types that want to meet the requirements for Pointer=
Like.<br></div><div><br></div><blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:=
1ex"><div dir=3D"ltr"><div class=3D"gmail_quote"><div></div><div>More weakl=
y, I wouldn't necessarily expect <font face=3D"monospace, monospace">p =
=3D=3D q</font> or <font face=3D"monospace, monospace">p !=3D q</font> to w=
ork. There are some algorithms that might require both PointerLike and Equa=
lityComparable, but I can think of many algorithms (e.g. <font face=3D"mono=
space, monospace">iter_swap</font>) that require PointerLike <i>without</i>=
EqualityComparable.=C2=A0 That said, I can't off the top of my head th=
ink of any "pointer-like" types that don't support the relati=
onal operators except for <a href=3D"https://github.com/Microsoft/GSL/blob/=
master/include/gsl/gsl#L72" target=3D"_blank">the GSL's <font face=3D"m=
onospace, monospace">nn<int*></font></a> (and I can only imagine that=
that was a horrific oversight).</div></div></div></blockquote><div><br></d=
iv><div>I'm not sure whether PointerLike needs to require relational op=
erators, but if they are defined, they must have reference semantics. I don=
't really see this requirement being much of an issue though. <br></div=
><div><br></div><div>And `not_null<T*>` implicitly converts to `T*`, =
so it does support comparison, among other things.<br></div></div></div></d=
iv>
<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/CAHocnE_-dK5A4cD6WGWGoSD51zY5DhTbej34=
OVELRsPgUXQufA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">htt=
ps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHocnE_-dK5A4cD6=
WGWGoSD51zY5DhTbej34OVELRsPgUXQufA%40mail.gmail.com</a>.<br />
--001a1145b3f076494e054891f168--
.
Author: "Arthur O'Dwyer" <arthur.j.odwyer@gmail.com>
Date: Wed, 15 Feb 2017 13:35:57 -0800
Raw View
--001a11444b525d4b780548987718
Content-Type: text/plain; charset=UTF-8
On Wed, Feb 15, 2017 at 5:49 AM, Joseph Thomson <joseph.thomson@gmail.com>
wrote:
> On Wed, Feb 15, 2017 at 4:13 PM, Arthur O'Dwyer <arthur.j.odwyer@gmail.com
> > wrote:
>
>> My kneejerk reaction is that even a "never null" pointer type ought to be
>> contextually convertible to bool. Its conversion function might be as
>> simple as
>>
>> constexpr operator bool() const noexcept { return true; }
>>
>> but it should still exist; otherwise you wouldn't be able to test the
>> pointer with "if (p)", which would make it unnecessarily awkward to drop
>> into existing codebases.
>> However, prior art seems to fall on the side of not allowing comparison
>> of known-non-null things with null things:
>>
>> - Dropbox's nn <https://github.com/dropbox/nn/blob/master/nn.hpp#L96>
>> doesn't provide operator bool()
>> - GSL's not_null
>> <https://github.com/Microsoft/GSL/blob/master/include/gsl/gsl#L72>
>> doesn't provide operator bool(), nor even relational operators == !=
>> - Martin Moene's not_null
>> <https://github.com/martinmoene/gsl-lite/blob/master/include/gsl/gsl-lite.h#L856>
>> doesn't provide operator bool()
>>
>
> I initially thought so too, but I think it is good design to only include
> features that have a purpose. Omitting conversion to `bool` may actually
> simplify user code by causing removal of pointless conditional statements.
>
Right, I think that's basically their rationale. They're saying "Comparison
of a known non-null pointer to NULL is probably a bug, so let's produce a
diagnostic when it happens." I'd have preferred to see a non-fatal
diagnostic; unfortunately there's no portable way to produce a non-fatal
diagnostic AFAIK.
>
>
>> Now, we could still do something like
>>
>> template<typename T>
>> auto GETPOINTER(T&& t) {
>> if constexpr(is_convertible_v<T&&, bool>) {
>> return bool(t) ? std::addressof(*t) : nullptr;
>> }
>> return std::addressof(*t);
>> }
>>
>
> That would only work if the behaviour of `GETPOINTER(p)` were undefined
> for contiguous past-the-end iterators (and I think it should be defined).
>
> Question, mostly whimsical: What would you expect to happen if I provided
>> an AlwaysNull<T> type that was the complementary type to NotNull<T>? That
>> is,
>>
>> int i = 42;
>> AlwaysNull<int *> an = nullptr; // ok
>> AlwaysNull<int *> an2 = &i; // runtime error
>> if (an) { ... } // compile-time error: AlwaysNull<int *> is not
>> convertible to bool because "that would be silly
>> <https://github.com/dropbox/nn/blob/master/nn.hpp#L93>"
>>
>> If this happened, would you want GETPOINTER(an) to "do the right thing"
>> and return nullptr, or would you want it to have undefined behavior, or
>> what?
>>
>
> It should return a null pointer. It's a bit of a pointless type though.
>
I agree that AlwaysNull<T> is a bit of a pointless type. ;) However,
thinking about corner cases can help clarify the problems we're talking
about. In this case, the problem is that AlwaysNull<T> and NeverNull<T>
have exactly the same public interface (same base classes, same members,
same free functions): they differ only in the abstract ideas behind them,
not in the public interface. So Concepts Lite cannot distinguish between
them.
>
>
>>> Now, there is still a problem, even in my happy world where all
>>>> "pointer-like" types implement operator*. The problem is that
>>>> sometimes a pointer can be non-null and *still* not point to an
>>>> object. [...]
>>>>
>>>
>> I don't see any reason to define the behavior of GETPOINTER(a.end())
>> given that there flatly *is no object* at any memory address that could
>> reasonably be associated with a.end(). If I understand correctly, we're
>> in agreement that GETPOINTER(a.end()) should be undefined for e.g. std::list<int>
>> a; we're only in disagreement about whether it should be defined for
>> std::vector and std::array.
>>
>
> Pointers do not have to point to valid objects. It makes sense that *all*
> contiguous iterators map to a valid pointer because this mapping is well
> defined. Making an exception for past-the-end iterators would complicate
> things enormously. Consider how one might implement GSL's `span` type:
>
> T* b_ptr;
> T* e_ptr;
>
> template <typename ContiguousIterator>
> span(ContiguousIterator b, ContiguousIterator e) :
> b_ptr(get_pointer(b)),
> e_ptr(get_pointer(e))
> {
> }
>
Okay, that's fair. You've convinced me that get_pointer(e) should return
the past-the-end pointer.
template<typename T>
auto *GETPOINTER*(T&& t) {
if constexpr(*IS_CONTIGUOUS_ITERATOR_V*<std::remove_reference_t<T>>)
{
return *SOME MAGIC INVOLVING A CUSTOMIZATION POINT*(t);
}
if constexpr(is_convertible_v<T&&, bool>) {
return bool(t) ? std::addressof(*t) : nullptr;
}
return std::addressof(*t);
}
There are at least four "proposals" on the table for the text of *SOME
MAGIC INVOLVING A CUSTOMIZATION POINT*.
(A) Nevin Liber's N3884
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf>
proposed (ADL) do_pointer_from(t).
(B) Joseph Thomson (you) seem to propose static_cast<T*>(t).
(C) Jonathan Coe's N4388
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4388.html>
(propagate_const)
seems to propose t.get().
(D) Nobody has proposed, but IMHO it should be considered, to just make &*t
well-defined somehow, since that's what people are doing today in practice.
(For the text of *IS_CONTIGUOUS_ITERATOR_V*, Nevin Liber's N3884
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf>
proposed literally is_contiguous_iterator_v
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf>; and
someone at the 2014 Issaquah meeting [private wiki]
<http://wiki.edg.com/bin/view/Wg21issaquah/N3884> suggested SFINAE on the
existence of (ADL) do_pointer_from(t).)
On (B), notice that arbitrary contiguous iterators aren't necessarily
convertible to pointers. This is actually listed as a benefit e.g. here
<http://codereview.stackexchange.com/questions/113866/the-final-word-on-contiguous-iterators#comment210916_113870>
and here <http://stackoverflow.com/a/32702585/1424877>. After all, if I
wanted a type that behaved like T* and *was* implicitly convertible to T*,
I would just use T*!
Jens Maurer's N4284
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4284.html>
proposed wording for "contiguous containers" and "contiguous iterators"
without proposing std::contiguous_iterator_tag nor std::pointer_from. N4284
has been adopted in C++17: see N4618
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4618.pdf> 24.2.1
[iterator.requirements.general] /6. Jens remarked that at the 2014
Issaquah meeting contiguous_iterator_tag "was found to break code,"
whatever that means.
From the meeting notes, it sounds like a major point of contention with
Nevin's N3884 was that it introduced a customization point, and
customization points are painful as hell. (See: std::swap.)
Another (minor?) point of contention was whether std::pointer_from should
also be defined to work on smart pointers, or *just* on contiguous
iterators. Nobody seems to have been talking about "pointer-like types" at
that point; the only problem in scope was how the user-programmer is
supposed to extract a past-the-end pointer from a past-the-end contiguous
iterator without invoking UB. (And this problem does not seem to have been
solved, as of C++17.)
If I were going to standardize a PointerLike concept, I would probably do
>>> something like this: an object `p` (and object `q` of the same type) is
>>> of PointerLike type if for some type `T`:
>>>
>>> - `static_cast<T*>(p)` is a valid expression
>>> - `*p` is equivalent to `*static_cast<T*>(p)`
>>> - `p.operator->()` is equivalent to `static_cast<T*>(p)`
>>> - `p == q` is equivalent to `static_cast<T*>(p) == static_cast<T*>(
>>> q)`
>>> - `p != q` is equivalent to `!(p == q)`
>>>
>>> I would say simply
>>
>> template<typename T>
>> concept bool PointerLike() {
>> return requires(T p) {
>> { *p };
>> };
>> }
>>
>> template<typename T>
>> concept bool NullablePointerLike() {
>> return PointerLike<T>() && requires(T p) {
>> { p } -> bool;
>> };
>> }
>>
>
> Not all types that define the indirection operators are pointer-like, for
> example, `optional<T>`. That's why I include the requirement that
> comparison be equivalent to comparing the underlying pointers (i.e.
> reference semantics). There needs to be some way to distinguish value types
> that implement `*` and `->` from pointer-like types.
>
But even if we allow for the sake of argument that static_cast<T*>(p)
compiles, I don't see how you propose to check at compile-time that "p == q is
equivalent to static_cast<T*>(p) == static_cast<T*>(q)" for all possible
values of p and q!
I definitely would not expect static_cast<T*>(p) to work; for example it
>> doesn't work for std::shared_ptr
>> <http://en.cppreference.com/w/cpp/memory/shared_ptr> or std::unique_ptr
>> <http://en.cppreference.com/w/cpp/memory/unique_ptr>, which IMNSHO
>> certainly ought to be considered "pointer-like types".
>>
>
> Explicit conversion to `T*` would be added for these types, and any other
> types that want to meet the requirements for PointerLike.
>
That's a non-starter. Getting a raw unmanaged pointer out of a managed
pointer is *deliberately* not something you can do with type conversions;
it *deliberately requires* extra typing. (Not to mention, it would break
existing code to add such a conversion, even as an explicit conversion.
Explicit conversions are relevant to SFINAE.)
>
> More weakly, I wouldn't necessarily expect p == q or p != q to work.
>> There are some algorithms that might require both PointerLike and
>> EqualityComparable, but I can think of many algorithms (e.g. iter_swap)
>> that require PointerLike *without* EqualityComparable. That said, I
>> can't off the top of my head think of any "pointer-like" types that don't
>> support the relational operators except for the GSL's nn<int*>
>> <https://github.com/Microsoft/GSL/blob/master/include/gsl/gsl#L72> (and
>> I can only imagine that that was a horrific oversight).
>>
>
> I'm not sure whether PointerLike needs to require relational operators,
> but if they are defined, they must have reference semantics. I don't really
> see this requirement being much of an issue though.
>
> And `not_null<T*>` implicitly converts to `T*`, so it does support
> comparison, among other things.
>
Whoops, that's my bad! You're correct. So gsl::not_null<T*> does support
contextual conversion to bool
<http://melpon.org/wandbox/permlink/QdppedRG9uxA7fLS> and so on, as well.
Man, implicit conversions are the bane of my existence. ;)
Here's the chart, updated:
A B C D E F
int* Y Y Y Y . Y
shared_ptr<int> Y . Y Y Y Y
unique_ptr<int> Y . Y Y Y Y
Dropbox nn<int*> . Y Y Y . Y
Dropbox nn<shared_ptr<int>> . . Y Y Y Y
gsl::not_null<int*> *Y* Y *Y* Y Y *Y*
std::vector<int>::iterator . . . Y . Y
std::list<int>::iterator . . . Y . Y
istream_iterator<int> . . . Y . Y
ostream_iterator<int> . . . Y . .
std::nullptr_t Y Y Y . . Y
void* Y Y Y . . Y
std::exception_ptr Y . Y . . Y
std::optional<int> Y . . Y . Y
std::future<int> . . . . Y .
std::reference_wrapper<int> . . . . Y Y
A: static_cast<bool>(p)
B: static_cast<int*>(p)
C: p == nullptr
D: *p
E: p.get()
F: p == q
--
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/CADvuK0JQxijd0NN3_HuN5H4gn5UGyr6fV8vJAKb-ewdhwkM7vw%40mail.gmail.com.
--001a11444b525d4b780548987718
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Wed, Feb 15, 2017 at 5:49 AM, Joseph Thomson <span dir=
=3D"ltr"><<a href=3D"mailto:joseph.thomson@gmail.com" target=3D"_blank">=
joseph.thomson@gmail.com</a>></span> wrote:<br><div class=3D"gmail_extra=
"><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"mar=
gin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,2=
04);border-left-style:solid;padding-left:1ex"><div dir=3D"ltr"><div class=
=3D"gmail_extra"><div class=3D"gmail_quote"><span class=3D"gmail-">On Wed, =
Feb 15, 2017 at 4:13 PM, Arthur O'Dwyer <span dir=3D"ltr"><<a href=
=3D"mailto:arthur.j.odwyer@gmail.com" target=3D"_blank">arthur.j.odwyer@gma=
il.com</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"=
margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;bord=
er-left-color:rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><span cla=
ss=3D"gmail-m_-3618923533677495598gmail-"></span><div class=3D"gmail_quote"=
><span class=3D"gmail-m_-3618923533677495598gmail-"></span><div>My kneejerk=
reaction is that even a "never null" pointer type ought to be co=
ntextually convertible to bool. Its conversion function might be as simple =
as</div><div><br></div><div>=C2=A0 =C2=A0 constexpr operator bool() const n=
oexcept { return true; }</div><div><br></div><div>but it should still exist=
; otherwise you wouldn't be able to test the pointer with "if (p)&=
quot;, which would make it unnecessarily awkward to drop into existing code=
bases.</div><div>However, prior art seems to fall on the side of not allowi=
ng comparison of known-non-null things with null things:</div><div><br></di=
v><div>- <a href=3D"https://github.com/dropbox/nn/blob/master/nn.hpp#L96" t=
arget=3D"_blank">Dropbox's nn</a> doesn't provide operator bool()</=
div><div>- <a href=3D"https://github.com/Microsoft/GSL/blob/master/include/=
gsl/gsl#L72" target=3D"_blank">GSL's not_null</a> doesn't provide o=
perator bool(), nor even relational operators =3D=3D !=3D</div><div>- <a hr=
ef=3D"https://github.com/martinmoene/gsl-lite/blob/master/include/gsl/gsl-l=
ite.h#L856" target=3D"_blank">Martin Moene's not_null</a> doesn't p=
rovide operator bool()<br></div></div></div></blockquote><div><br></div></s=
pan><div>I initially thought so too, but I think it is good design to only =
include features that have a purpose. Omitting conversion to `bool` may act=
ually simplify user code by causing removal of pointless conditional statem=
ents.<br></div></div></div></div></blockquote><div><br></div><div>Right, I =
think that's basically their rationale. They're saying "Compar=
ison of a known non-null pointer to NULL is probably a bug, so let's pr=
oduce a diagnostic when it happens." I'd have preferred to see a n=
on-fatal diagnostic; unfortunately there's no portable way to produce a=
non-fatal diagnostic AFAIK.</div><div>=C2=A0</div><blockquote class=3D"gma=
il_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-le=
ft-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div di=
r=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><div></div>=
<span class=3D"gmail-"><div>=C2=A0</div><blockquote class=3D"gmail_quote" s=
tyle=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:so=
lid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><=
div class=3D"gmail_quote"><div>Now, we could still do something like</div><=
span class=3D"gmail-m_-3618923533677495598gmail-"><div><br></div><div><font=
face=3D"monospace, monospace">=C2=A0 =C2=A0 template<typename T></fo=
nt></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 auto GETPOI=
NTER(T&& t) {</font></div></span><div><font face=3D"monospace, mono=
space">=C2=A0 =C2=A0 =C2=A0 =C2=A0 if constexpr(is_convertible_v<T&&=
amp;<wbr>, bool>) {</font></div><div><font face=3D"monospace, monospace"=
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return bool(t) ?=C2=A0</font><sp=
an style=3D"font-family:monospace,monospace">std::addressof(*t) : nullptr;<=
/span></div><div><span style=3D"font-family:monospace,monospace">=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 }</span><br></div><div><font face=3D"monospace, monospace=
">=C2=A0 =C2=A0 =C2=A0 =C2=A0 return std::addressof(*t);</font></div><div><=
font face=3D"monospace, monospace">=C2=A0 =C2=A0 }</font></div></div></div>=
</blockquote><div>=C2=A0<br></div></span><div>That would only work if the b=
ehaviour of `GETPOINTER(p)` were undefined for contiguous past-the-end iter=
ators (and I think it should be defined).<br></div><span class=3D"gmail-"><=
div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(=
204,204,204);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_quote">=
<div></div><div>Question, mostly whimsical: What would you expect to happen=
if I provided an AlwaysNull<T> type that was the complementary type =
to NotNull<T>?=C2=A0 That is,</div><div><br></div><div><font face=3D"=
monospace, monospace">=C2=A0 =C2=A0 int i =3D 42;</font></div><div><font fa=
ce=3D"monospace, monospace">=C2=A0 =C2=A0 AlwaysNull<int *> an =3D nu=
llptr; // ok</font></div><div><font face=3D"monospace, monospace">=C2=A0 =
=C2=A0 AlwaysNull<int *> an2 =3D &i; =C2=A0// runtime error</font=
></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 if (an) { ...=
} =C2=A0// compile-time error: AlwaysNull<int *> is not convertible =
to bool because "<a href=3D"https://github.com/dropbox/nn/blob/master/=
nn.hpp#L93" target=3D"_blank">that would be silly</a>"</font></div><di=
v><br></div><div>If this happened, would you want <font face=3D"monospace, =
monospace">GETPOINTER(an)</font> to "do the right thing" and retu=
rn nullptr, or would you want it to have undefined behavior, or what?</div>=
<span class=3D"gmail-m_-3618923533677495598gmail-"></span></div></div></blo=
ckquote><div><br></div></span><div>It should return a null pointer. It'=
s a bit of a pointless type though.<br></div></div></div></div></blockquote=
><div><br></div><div>I agree that AlwaysNull<T> is a bit of a pointle=
ss type. ;) =C2=A0However, thinking about corner cases can help clarify the=
problems we're talking about. In this case, the problem is that Always=
Null<T> and NeverNull<T> have exactly the same public interface=
(same base classes, same members, same free functions): they differ only i=
n the abstract ideas behind them, not in the public interface. So Concepts =
Lite cannot distinguish between them.</div><div><br></div><div>=C2=A0</div>=
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-=
left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p=
adding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"=
gmail_quote"><div></div><span class=3D"gmail-"><div><br></div><blockquote c=
lass=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1p=
x;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1=
ex"><div dir=3D"ltr"><div class=3D"gmail_quote"><span class=3D"gmail-m_-361=
8923533677495598gmail-"><blockquote class=3D"gmail_quote" style=3D"margin:0=
px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-=
color:rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gma=
il_extra"><div class=3D"gmail_quote"><span class=3D"gmail-m_-36189235336774=
95598gmail-m_428563140955204213gmail-"><div><br></div><blockquote class=3D"=
gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border=
-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div=
dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><div>Now=
, there is still a problem, even in my happy world where all "pointer-=
like" types implement <font face=3D"monospace, monospace">operator*</f=
ont>. The problem is that sometimes a pointer can be non-null and <i>still<=
/i> not point to an object. [...]</div></div></div></div></blockquote></spa=
n></div></div></div></blockquote><div><br></div></span><div>I don't see=
any reason to define the behavior of <font face=3D"monospace, monospace">G=
ETPOINTER(a.end())</font> given that there flatly <i>is no object</i> at an=
y memory address that could reasonably be associated with <font face=3D"mon=
ospace, monospace">a.end()</font>. If I understand correctly, we're in =
agreement that <font face=3D"monospace, monospace">GETPOINTER(a.end())</fon=
t> should be undefined for e.g. <font face=3D"monospace, monospace">std::li=
st<int> a</font>; we're only in disagreement about whether it sho=
uld be defined for std::vector and std::array.</div></div></div></blockquot=
e><div><br></div></span><div>Pointers do not have to point to valid objects=
.. It makes sense that <i>all</i> contiguous iterators map to a valid pointe=
r because this mapping is well defined. Making an exception for past-the-en=
d iterators would complicate things enormously. Consider how one might impl=
ement GSL's `span` type:<br></div><div><br></div><div style=3D"margin-l=
eft:40px"><span style=3D"font-family:monospace,monospace">T* b_ptr;<br></sp=
an></div><div style=3D"margin-left:40px"><span style=3D"font-family:monospa=
ce,monospace">T* e</span><span style=3D"font-family:monospace,monospace"><s=
pan style=3D"font-family:monospace,monospace">_ptr</span>;<br><br></span></=
div><div style=3D"margin-left:40px"><span style=3D"font-family:monospace,mo=
nospace">template <typename ContiguousIterator><br></span></div><div =
style=3D"margin-left:40px"><span style=3D"font-family:monospace,monospace">=
span(ContiguousIterator b, ContiguousIterator e) :<br></span></div><div sty=
le=3D"margin-left:40px"><span style=3D"font-family:monospace,monospace">=C2=
=A0=C2=A0=C2=A0 b</span><span style=3D"font-family:monospace,monospace"><sp=
an style=3D"font-family:monospace,monospace">_ptr</span>(get_pointer(b)),<b=
r>=C2=A0=C2=A0=C2=A0 e</span><span style=3D"font-family:monospace,monospace=
"><span style=3D"font-family:monospace,monospace">_ptr</span>(get_pointer(e=
))<br></span></div><div style=3D"margin-left:40px"><span style=3D"font-fami=
ly:monospace,monospace">{<br>}</span></div></div></div></div></blockquote><=
div><br></div><div>Okay, that's fair. You've convinced me that <fon=
t face=3D"monospace, monospace">get_pointer(e)</font> should return the pas=
t-the-end pointer.</div><div><br></div><div><span class=3D"gmail-m_-3618923=
533677495598gmail-"><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =
template<typename T></font></div><div><font face=3D"monospace, monosp=
ace">=C2=A0 =C2=A0 auto <i>GETPOINTER</i>(T&& t) {</font></div><div=
><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 if constex=
pr(<i>IS_CONTIGUOUS_ITERATOR_V</i><std::remove_reference_t<T>>)=
{</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 return <i>SOME MAGIC INVOLVING A CUSTOMIZATION POI=
NT</i>(t);</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 }</font></div></span><div><font face=3D"monospace, monosp=
ace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 if constexpr(is_convertible_v<T&&am=
p;<wbr>, bool>) {</font></div><div><font face=3D"monospace, monospace">=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return bool(t) ?=C2=A0</font><spa=
n style=3D"font-family:monospace,monospace">std::addressof(*t) : nullptr;</=
span></div><div><span style=3D"font-family:monospace,monospace">=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 }</span><br></div><div><font face=3D"monospace, monospace=
">=C2=A0 =C2=A0 =C2=A0 =C2=A0 return std::addressof(*t);</font></div><div><=
font face=3D"monospace, monospace">=C2=A0 =C2=A0 }</font></div></div><div c=
lass=3D"gmail_quote"><br></div><div class=3D"gmail_quote">There are at leas=
t four "proposals" on the table for the text of <i><font face=3D"=
monospace, monospace">SOME MAGIC INVOLVING A CUSTOMIZATION POINT</font></i>=
..<br></div><div class=3D"gmail_quote">(A) Nevin Liber's <a href=3D"http=
://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf">N3884</a> pr=
oposed (ADL) <font face=3D"monospace, monospace">do_pointer_from(t)</font>.=
</div><div class=3D"gmail_quote">(B) Joseph Thomson (you) seem to propose <=
font face=3D"monospace, monospace">static_cast<T*>(t)</font>.</div><d=
iv class=3D"gmail_quote">(C) Jonathan Coe's <a href=3D"http://www.open-=
std.org/jtc1/sc22/wg21/docs/papers/2015/n4388.html">N4388</a>=C2=A0(propaga=
te_const) seems to propose=C2=A0<font face=3D"monospace, monospace">t.get()=
</font>.</div>(D) Nobody has proposed, but IMHO it should be considered, to=
just make <font face=3D"monospace, monospace">&*t</font> well-defined =
somehow, since that's what people are doing today in practice.</div><di=
v class=3D"gmail_quote"><br></div><div class=3D"gmail_quote"><div class=3D"=
gmail_quote">(For the text of <font face=3D"monospace, monospace"><i>IS_CON=
TIGUOUS_ITERATOR_V</i></font>, Nevin Liber's <a href=3D"http://www.open=
-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf">N3884</a> proposed lite=
rally=C2=A0<font face=3D"monospace, monospace"><a href=3D"http://www.open-s=
td.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf">is_contiguous_iterator_v<=
/a></font>; and someone at the 2014 Issaquah meeting=C2=A0<a href=3D"http:/=
/wiki.edg.com/bin/view/Wg21issaquah/N3884">[private wiki]</a>=C2=A0suggeste=
d SFINAE on the existence of (ADL)=C2=A0<font face=3D"monospace, monospace"=
>do_pointer_from(t)</font>.)</div><div><br></div></div><div class=3D"gmail_=
quote">On (B), notice that arbitrary contiguous iterators aren't necess=
arily convertible to pointers. This is actually listed as a benefit e.g. <a=
href=3D"http://codereview.stackexchange.com/questions/113866/the-final-wor=
d-on-contiguous-iterators#comment210916_113870">here</a> and <a href=3D"htt=
p://stackoverflow.com/a/32702585/1424877">here</a>. After all, if I wanted =
a type that behaved like <font face=3D"monospace, monospace">T*</font> and =
<i>was</i> implicitly convertible to <font face=3D"monospace, monospace">T*=
</font>, I would just use <font face=3D"monospace, monospace">T*</font>!<di=
v><br></div><div>Jens Maurer's <a href=3D"http://www.open-std.org/jtc1/=
sc22/wg21/docs/papers/2014/n4284.html">N4284</a> proposed wording for "=
;contiguous containers" and "contiguous iterators" without p=
roposing <font face=3D"monospace, monospace">std::contiguous_iterator_tag</=
font> nor <font face=3D"monospace, monospace">std::pointer_from</font>. N42=
84 has been adopted in C++17: see <a href=3D"http://www.open-std.org/jtc1/s=
c22/wg21/docs/papers/2016/n4618.pdf">N4618</a> 24.2.1 [iterator.requirement=
s.general] /6.=C2=A0 Jens remarked that at the 2014 Issaquah meeting=C2=A0<=
font face=3D"monospace, monospace">contiguous_iterator_tag</font> "was=
found to break code," whatever that means.<br></div><div>From the mee=
ting notes, it sounds like a major point of contention with Nevin's N38=
84 was that it introduced a customization point, and customization points a=
re painful as hell. (See: <font face=3D"monospace, monospace">std::swap</fo=
nt>.)</div><div>Another (minor?) point of contention was whether <font face=
=3D"monospace, monospace">std::pointer_from</font> should also be defined t=
o work on smart pointers, or <i>just</i> on contiguous iterators. Nobody se=
ems to have been talking about "pointer-like types" at that point=
; the only problem in scope was how the user-programmer is supposed to extr=
act a past-the-end pointer from a past-the-end contiguous iterator without =
invoking UB. (And this problem does not seem to have been solved, as of C++=
17.)</div><div><br></div><div><br></div><div><br></div><blockquote class=3D=
"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;borde=
r-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><di=
v dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><span c=
lass=3D"gmail-"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rg=
b(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_quote=
"><span class=3D"gmail-m_-3618923533677495598gmail-"><blockquote class=3D"g=
mail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-=
left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div =
dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><div>If I=
were going to standardize a <span style=3D"font-family:monospace,monospace=
">PointerLike</span> concept, I would probably do something like this: an o=
bject <span style=3D"font-family:monospace,monospace">`p`</span> (and objec=
t <span style=3D"font-family:monospace,monospace">`q`</span> of the same ty=
pe) is of <span style=3D"font-family:monospace,monospace">PointerLike</span=
> type if for some type <span style=3D"font-family:monospace,monospace">`T`=
</span>:<br></div><div><ul><li><span style=3D"font-family:monospace,monospa=
ce">`static_cast<T*>(p)`</span> is a valid expression<br><span style=
=3D"font-family:monospace,monospace"></span></li><li><span style=3D"font-fa=
mily:monospace,monospace">`*p`</span> is equivalent to <span style=3D"font-=
family:monospace,monospace">`*static_cast<T*>(p)`</span></li><li><spa=
n style=3D"font-family:monospace,monospace">`p.operator->()`</span><span=
style=3D"font-family:arial,helvetica,sans-serif"> is equivalent to </span>=
<span style=3D"font-family:monospace,monospace">`static_cast<T*>(p)`<=
br></span></li><li><span style=3D"font-family:monospace,monospace">`p =3D=
=3D q`</span> is equivalent to <span style=3D"font-family:monospace,monospa=
ce"><span style=3D"font-family:monospace,monospace">`static_cast<T*>(=
</span>p) =3D=3D </span><span style=3D"font-family:monospace,monospace"><sp=
an style=3D"font-family:monospace,monospace">static_cast<T*>(</span>q=
)`</span></li><li><span style=3D"font-family:monospace,monospace">`p !=3D q=
`</span> is equivalent to <span style=3D"font-family:monospace,monospace">`=
!(p =3D=3D q)`</span></li></ul></div></div></div></div></blockquote></span>=
<div>I would say simply</div><div><br></div><div><font face=3D"monospace, m=
onospace">template<typename T></font></div><div><font face=3D"monospa=
ce, monospace">concept bool PointerLike() {</font></div><div><font face=3D"=
monospace, monospace">=C2=A0 =C2=A0 return requires(T p) {</font></div><div=
><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 { *p };</f=
ont></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 };<br></fo=
nt></div><div><font face=3D"monospace, monospace">}</font></div><div><font =
face=3D"monospace, monospace"><br></font></div><div><div><font face=3D"mono=
space, monospace">template<typename T></font></div><div><font face=3D=
"monospace, monospace">concept bool NullablePointerLike() {</font></div><di=
v><font face=3D"monospace, monospace">=C2=A0 =C2=A0 return PointerLike<T=
>() && requires(T p) {</font></div><div><font face=3D"monospace,=
monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 { p } -> bool;</font></div><div>=
<font face=3D"monospace, monospace">=C2=A0 =C2=A0 };</font></div><div><font=
face=3D"monospace, monospace">}<br></font></div></div></div></div></blockq=
uote><div><br></div></span><div>Not all types that define the indirection o=
perators are pointer-like, for example, `optional<T>`. That's why=
I include the requirement that comparison be equivalent to comparing the u=
nderlying pointers (i.e. reference semantics). There needs to be some way t=
o distinguish value types that implement `*` and `->` from pointer-like =
types.<br></div></div></div></div></blockquote><div><br></div><div>But even=
if we allow for the sake of argument that <font face=3D"monospace, monospa=
ce">static_cast<T*>(p)</font> compiles, I don't see how you propo=
se to check at compile-time that "<span style=3D"font-family:monospace=
,monospace">p =3D=3D q</span>=C2=A0is equivalent to=C2=A0<span style=3D"fon=
t-family:monospace,monospace">static_cast<T*>(p) =3D=3D=C2=A0</span><=
span style=3D"font-family:monospace,monospace">static_cast<T*>(q)</sp=
an>" for all possible values of <font face=3D"monospace, monospace">p<=
/font> and <font face=3D"monospace, monospace">q</font>!</div><div><br></di=
v><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;borde=
r-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid=
;padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><div class=
=3D"gmail_quote"><span class=3D"gmail-"><blockquote class=3D"gmail_quote" s=
tyle=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:so=
lid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><=
div class=3D"gmail_quote"><div></div><div>I definitely would not expect <fo=
nt face=3D"monospace, monospace">static_cast<T*>(p)</font> to work; f=
or example it doesn't work for <a href=3D"http://en.cppreference.com/w/=
cpp/memory/shared_ptr" target=3D"_blank">std::shared_ptr</a> or <a href=3D"=
http://en.cppreference.com/w/cpp/memory/unique_ptr" target=3D"_blank">std::=
unique_ptr</a>, which IMNSHO certainly ought to be considered "pointer=
-like types".</div></div></div></blockquote><div>=C2=A0<br></div></spa=
n><div>Explicit conversion to `T*` would be added for these types, and any =
other types that want to meet the requirements for PointerLike.<br></div></=
div></div></div></blockquote><div><br></div><div>That's a non-starter. =
Getting a raw unmanaged pointer out of a managed pointer is <i>deliberately=
</i> not something you can do with type conversions; it <i>deliberately=C2=
=A0requires</i> extra typing. (Not to mention, it would break existing code=
to add such a conversion, even as an <font face=3D"monospace, monospace">e=
xplicit</font> conversion. Explicit conversions are relevant to SFINAE.)</d=
iv><div><br></div><div>=C2=A0</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 =
class=3D"gmail_extra"><div class=3D"gmail_quote"><div></div><span class=3D"=
gmail-"><div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0p=
x 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-c=
olor:rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmai=
l_quote"><div></div><div>More weakly, I wouldn't necessarily expect <fo=
nt face=3D"monospace, monospace">p =3D=3D q</font> or <font face=3D"monospa=
ce, monospace">p !=3D q</font> to work. There are some algorithms that migh=
t require both PointerLike and EqualityComparable, but I can think of many =
algorithms (e.g. <font face=3D"monospace, monospace">iter_swap</font>) that=
require PointerLike <i>without</i> EqualityComparable.=C2=A0 That said, I =
can't off the top of my head think of any "pointer-like" type=
s that don't support the relational operators except for <a href=3D"htt=
ps://github.com/Microsoft/GSL/blob/master/include/gsl/gsl#L72" target=3D"_b=
lank">the GSL's <font face=3D"monospace, monospace">nn<int*></fon=
t></a> (and I can only imagine that that was a horrific oversight).</div></=
div></div></blockquote><div><br></div></span><div>I'm not sure whether =
PointerLike needs to require relational operators, but if they are defined,=
they must have reference semantics. I don't really see this requiremen=
t being much of an issue though. <br></div><div><br></div><div>And `not_nul=
l<T*>` implicitly converts to `T*`, so it does support comparison, am=
ong other things.<br></div></div></div></div></blockquote><div><br></div><d=
iv>Whoops, that's my bad! You're correct. So gsl::not_null<T*>=
; <a href=3D"http://melpon.org/wandbox/permlink/QdppedRG9uxA7fLS">does supp=
ort contextual conversion to bool</a> and so on, as well.</div><div>Man, im=
plicit conversions are the bane of my existence. ;)</div><div><br></div><di=
v>Here's the chart, updated:</div><div><br></div><div><div style=3D"fon=
t-size:13px"><span style=3D"font-family:monospace,monospace">=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 A B C D E F</span></div><div style=3D"font-size:13px"><span styl=
e=3D"font-family:monospace,monospace">int* =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Y Y Y Y . Y</span><br><=
/div><div style=3D"font-size:13px"><font face=3D"monospace, monospace">shar=
ed_ptr<int> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Y . Y Y Y Y</fo=
nt></div><div style=3D"font-size:13px"><font face=3D"monospace, monospace">=
unique_ptr<int> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Y . Y Y Y Y=
</font></div><div style=3D"font-size:13px"><font face=3D"monospace, monospa=
ce">Dropbox nn<int*> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0. Y Y Y=
. Y</font></div><div style=3D"font-size:13px"><font face=3D"monospace, mon=
ospace">Dropbox nn<shared_ptr<int>> . . Y Y Y Y</font></div><di=
v style=3D"font-size:13px"><span style=3D"font-family:monospace,monospace">=
gsl::not_null<int*> =C2=A0 =C2=A0 =C2=A0 =C2=A0 <b>Y</b> Y <b>Y</b> Y=
Y <b>Y</b></span><br></div><div style=3D"font-size:13px"><span style=3D"fo=
nt-family:monospace,monospace">std::vector<int>::iterator =C2=A0. . .=
Y . Y</span><br></div><div style=3D"font-size:13px"><span style=3D"font-fa=
mily:monospace,monospace">std::list<int>::iterator =C2=A0 =C2=A0. . .=
Y . Y</span></div><div style=3D"font-size:13px"><div><span style=3D"font-f=
amily:monospace,monospace">istream_iterator<int> =C2=A0 =C2=A0 =C2=A0=
. . . Y . Y</span><br></div><div><span style=3D"font-family:monospace,mono=
space">ostream_iterator<int> =C2=A0 =C2=A0 =C2=A0 . . . Y . .</span><=
/div><div><span style=3D"font-family:monospace,monospace">std::nullptr_t =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Y Y Y . . Y</span><br></div=
><div><font face=3D"monospace, monospace">void* =C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Y Y Y . . Y</font></div><=
div><span style=3D"font-family:monospace,monospace">std::exception_ptr =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Y . Y . . Y</span></div><div><span style=3D"=
font-family:monospace,monospace">std::optional<int> =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0Y . . Y . Y</span></div><div><span style=3D"font-family:mo=
nospace,monospace">std::future<int> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0. . . . Y .</span></div><div><span style=3D"font-family:monospace=
,monospace">std::reference_wrapper<int> . . . . Y Y</span></div><div>=
<br></div><div><span style=3D"font-family:monospace,monospace">A: static_ca=
st<bool>(p)</span></div></div><div style=3D"font-size:13px"><div><spa=
n style=3D"font-family:monospace,monospace">B: static_cast<int*>(p)</=
span></div><div><span style=3D"font-family:monospace,monospace">C: p =3D=3D=
nullptr</span></div><div><span style=3D"font-family:monospace,monospace">D=
: *p</span></div><div><span style=3D"font-family:monospace,monospace">E: p.=
get()</span></div></div><div style=3D"font-size:13px"><span style=3D"font-f=
amily:monospace,monospace">F: p =3D=3D q</span></div></div></div></div></di=
v>
<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/CADvuK0JQxijd0NN3_HuN5H4gn5UGyr6fV8vJ=
AKb-ewdhwkM7vw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">htt=
ps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0JQxijd0NN3=
_HuN5H4gn5UGyr6fV8vJAKb-ewdhwkM7vw%40mail.gmail.com</a>.<br />
--001a11444b525d4b780548987718--
.
Author: Joseph Thomson <joseph.thomson@gmail.com>
Date: Thu, 16 Feb 2017 08:43:54 +0800
Raw View
--94eb2c1b45d28855c005489b1777
Content-Type: text/plain; charset=UTF-8
On Thu, Feb 16, 2017 at 5:35 AM, Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
wrote:
> On Wed, Feb 15, 2017 at 5:49 AM, Joseph Thomson <joseph.thomson@gmail.com>
> wrote:
>
>> On Wed, Feb 15, 2017 at 4:13 PM, Arthur O'Dwyer <
>> arthur.j.odwyer@gmail.com> wrote:
>>
>>> My kneejerk reaction is that even a "never null" pointer type ought to
>>> be contextually convertible to bool. Its conversion function might be as
>>> simple as
>>>
>>> constexpr operator bool() const noexcept { return true; }
>>>
>>> but it should still exist; otherwise you wouldn't be able to test the
>>> pointer with "if (p)", which would make it unnecessarily awkward to drop
>>> into existing codebases.
>>> However, prior art seems to fall on the side of not allowing comparison
>>> of known-non-null things with null things:
>>>
>>> - Dropbox's nn <https://github.com/dropbox/nn/blob/master/nn.hpp#L96>
>>> doesn't provide operator bool()
>>> - GSL's not_null
>>> <https://github.com/Microsoft/GSL/blob/master/include/gsl/gsl#L72>
>>> doesn't provide operator bool(), nor even relational operators == !=
>>> - Martin Moene's not_null
>>> <https://github.com/martinmoene/gsl-lite/blob/master/include/gsl/gsl-lite.h#L856>
>>> doesn't provide operator bool()
>>>
>>
>> I initially thought so too, but I think it is good design to only include
>> features that have a purpose. Omitting conversion to `bool` may actually
>> simplify user code by causing removal of pointless conditional statements.
>>
>
> Right, I think that's basically their rationale. They're saying
> "Comparison of a known non-null pointer to NULL is probably a bug, so let's
> produce a diagnostic when it happens." I'd have preferred to see a
> non-fatal diagnostic; unfortunately there's no portable way to produce a
> non-fatal diagnostic AFAIK.
>
>
>>
>>
>>> Now, we could still do something like
>>>
>>> template<typename T>
>>> auto GETPOINTER(T&& t) {
>>> if constexpr(is_convertible_v<T&&, bool>) {
>>> return bool(t) ? std::addressof(*t) : nullptr;
>>> }
>>> return std::addressof(*t);
>>> }
>>>
>>
>> That would only work if the behaviour of `GETPOINTER(p)` were undefined
>> for contiguous past-the-end iterators (and I think it should be defined).
>>
>> Question, mostly whimsical: What would you expect to happen if I provided
>>> an AlwaysNull<T> type that was the complementary type to NotNull<T>? That
>>> is,
>>>
>>> int i = 42;
>>> AlwaysNull<int *> an = nullptr; // ok
>>> AlwaysNull<int *> an2 = &i; // runtime error
>>> if (an) { ... } // compile-time error: AlwaysNull<int *> is not
>>> convertible to bool because "that would be silly
>>> <https://github.com/dropbox/nn/blob/master/nn.hpp#L93>"
>>>
>>> If this happened, would you want GETPOINTER(an) to "do the right thing"
>>> and return nullptr, or would you want it to have undefined behavior, or
>>> what?
>>>
>>
>> It should return a null pointer. It's a bit of a pointless type though.
>>
>
> I agree that AlwaysNull<T> is a bit of a pointless type. ;) However,
> thinking about corner cases can help clarify the problems we're talking
> about. In this case, the problem is that AlwaysNull<T> and NeverNull<T>
> have exactly the same public interface (same base classes, same members,
> same free functions): they differ only in the abstract ideas behind them,
> not in the public interface. So Concepts Lite cannot distinguish between
> them.
>
Concepts
>>
>>>> Now, there is still a problem, even in my happy world where all
>>>>> "pointer-like" types implement operator*. The problem is that
>>>>> sometimes a pointer can be non-null and *still* not point to an
>>>>> object. [...]
>>>>>
>>>>
>>> I don't see any reason to define the behavior of GETPOINTER(a.end())
>>> given that there flatly *is no object* at any memory address that could
>>> reasonably be associated with a.end(). If I understand correctly, we're
>>> in agreement that GETPOINTER(a.end()) should be undefined for e.g. std::list<int>
>>> a; we're only in disagreement about whether it should be defined for
>>> std::vector and std::array.
>>>
>>
>> Pointers do not have to point to valid objects. It makes sense that *all*
>> contiguous iterators map to a valid pointer because this mapping is well
>> defined. Making an exception for past-the-end iterators would complicate
>> things enormously. Consider how one might implement GSL's `span` type:
>>
>> T* b_ptr;
>> T* e_ptr;
>>
>> template <typename ContiguousIterator>
>> span(ContiguousIterator b, ContiguousIterator e) :
>> b_ptr(get_pointer(b)),
>> e_ptr(get_pointer(e))
>> {
>> }
>>
>
> Okay, that's fair. You've convinced me that get_pointer(e) should return
> the past-the-end pointer.
>
> template<typename T>
> auto *GETPOINTER*(T&& t) {
> if constexpr(*IS_CONTIGUOUS_ITERATOR_V*<std::remove_reference_t<T>>)
> {
> return *SOME MAGIC INVOLVING A CUSTOMIZATION POINT*(t);
> }
> if constexpr(is_convertible_v<T&&, bool>) {
> return bool(t) ? std::addressof(*t) : nullptr;
> }
> return std::addressof(*t);
> }
>
> There are at least four "proposals" on the table for the text of *SOME
> MAGIC INVOLVING A CUSTOMIZATION POINT*.
> (A) Nevin Liber's N3884
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf>
> proposed (ADL) do_pointer_from(t).
> (B) Joseph Thomson (you) seem to propose static_cast<T*>(t).
> (C) Jonathan Coe's N4388
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4388.html> (propagate_const)
> seems to propose t.get().
> (D) Nobody has proposed, but IMHO it should be considered, to just make
> &*t well-defined somehow, since that's what people are doing today in
> practice.
>
> (For the text of *IS_CONTIGUOUS_ITERATOR_V*, Nevin Liber's N3884
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf>
> proposed literally is_contiguous_iterator_v
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf>; and
> someone at the 2014 Issaquah meeting [private wiki]
> <http://wiki.edg.com/bin/view/Wg21issaquah/N3884> suggested SFINAE on the
> existence of (ADL) do_pointer_from(t).)
>
> On (B), notice that arbitrary contiguous iterators aren't necessarily
> convertible to pointers. This is actually listed as a benefit e.g. here
> <http://codereview.stackexchange.com/questions/113866/the-final-word-on-contiguous-iterators#comment210916_113870>
> and here <http://stackoverflow.com/a/32702585/1424877>. After all, if I
> wanted a type that behaved like T* and *was* implicitly convertible to T*,
> I would just use T*!
>
If I understand correctly, these are benefits of disallowing *implicit*
conversion (the term "conversion" seems to be implicitly implicit, e.g.
`is_convertible`). Explicit conversion AFAIK represents a *subversion* of
the type system, and this is what I am suggesting.
From the meeting notes, it sounds like a major point of contention with
> Nevin's N3884 was that it introduced a customization point, and
> customization points are painful as hell. (See: std::swap.)
>
Customization points *are* painful, which is why I'm suggesting explicit
conversion to `T*`, which has the potential to work with both pointers *and*
pointer-like class types.
> Another (minor?) point of contention was whether std::pointer_from should
> also be defined to work on smart pointers, or *just* on contiguous
> iterators. Nobody seems to have been talking about "pointer-like types" at
> that point; the only problem in scope was how the user-programmer is
> supposed to extract a past-the-end pointer from a past-the-end contiguous
> iterator without invoking UB. (And this problem does not seem to have been
> solved, as of C++17.)
>
`propagate_const` is one use case for supporting all pointer-like types.
There are probably others I haven't thought of.
I definitely would not expect static_cast<T*>(p) to work; for example it
>>> doesn't work for std::shared_ptr or std::unique_ptr, which IMNSHO certainly
>>> ought to be considered "pointer-like types".
>>>
>>
>> Explicit conversion to `T*` would be added for these types, and any other
>> types that want to meet the requirements for PointerLike.
>>
>
> That's a non-starter. Getting a raw unmanaged pointer out of a managed
> pointer is deliberately not something you can do with type conversions; it
> deliberately requires extra typing. (Not to mention, it would break
> existing code to add such a conversion, even as an explicit conversion.
> Explicit conversions are relevant to SFINAE.)
As I mentioned above, it's my understanding that *explicit* conversion
represents a subversion of the type system, and is not something people are
likely to do by accident. In fact, IMO this:
auto p = static_cast<T*>(smart_pointer);
Is more explicit than this:
auto p = smart_pointer.get();
A `static_cast` is both more typing *and* it requires explicit
specification of the pointer type.
But I agree that if it breaks a not-insignificant amount of code then it's
a non-starter (which would be a shame). Would be helpful to have an example
though.
--
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/CAHocnE9BG%2BuceUxfy%3DcsFUcRm06u6LPdXTAcmWE9MHQSUeS_wA%40mail.gmail.com.
--94eb2c1b45d28855c005489b1777
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On T=
hu, Feb 16, 2017 at 5:35 AM, Arthur O'Dwyer <span dir=3D"ltr"><<a hr=
ef=3D"mailto:arthur.j.odwyer@gmail.com" target=3D"_blank">arthur.j.odwyer@g=
mail.com</a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding=
-left:1ex"><div dir=3D"ltr"><span class=3D"gmail-">On Wed, Feb 15, 2017 at =
5:49 AM, Joseph Thomson <span dir=3D"ltr"><<a href=3D"mailto:joseph.thom=
son@gmail.com" target=3D"_blank">joseph.thomson@gmail.com</a>></span> wr=
ote:<br></span><div class=3D"gmail_extra"><div class=3D"gmail_quote"><span =
class=3D"gmail-"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px =
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=
=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><span class=
=3D"gmail-m_-5930105264369399928gmail-">On Wed, Feb 15, 2017 at 4:13 PM, Ar=
thur O'Dwyer <span dir=3D"ltr"><<a href=3D"mailto:arthur.j.odwyer@gm=
ail.com" target=3D"_blank">arthur.j.odwyer@gmail.com</a>></span> wrote:<=
br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bord=
er-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><span=
class=3D"gmail-m_-5930105264369399928gmail-m_-3618923533677495598gmail-"><=
/span><div class=3D"gmail_quote"><span class=3D"gmail-m_-593010526436939992=
8gmail-m_-3618923533677495598gmail-"></span><div>My kneejerk reaction is th=
at even a "never null" pointer type ought to be contextually conv=
ertible to bool. Its conversion function might be as simple as</div><div><b=
r></div><div>=C2=A0 =C2=A0 constexpr operator bool() const noexcept { retur=
n true; }</div><div><br></div><div>but it should still exist; otherwise you=
wouldn't be able to test the pointer with "if (p)", which wo=
uld make it unnecessarily awkward to drop into existing codebases.</div><di=
v>However, prior art seems to fall on the side of not allowing comparison o=
f known-non-null things with null things:</div><div><br></div><div>- <a hre=
f=3D"https://github.com/dropbox/nn/blob/master/nn.hpp#L96" target=3D"_blank=
">Dropbox's nn</a> doesn't provide operator bool()</div><div>- <a h=
ref=3D"https://github.com/Microsoft/GSL/blob/master/include/gsl/gsl#L72" ta=
rget=3D"_blank">GSL's not_null</a> doesn't provide operator bool(),=
nor even relational operators =3D=3D !=3D</div><div>- <a href=3D"https://g=
ithub.com/martinmoene/gsl-lite/blob/master/include/gsl/gsl-lite.h#L856" tar=
get=3D"_blank">Martin Moene's not_null</a> doesn't provide operator=
bool()<br></div></div></div></blockquote><div><br></div></span><div>I init=
ially thought so too, but I think it is good design to only include feature=
s that have a purpose. Omitting conversion to `bool` may actually simplify =
user code by causing removal of pointless conditional statements.<br></div>=
</div></div></div></blockquote><div><br></div></span><div>Right, I think th=
at's basically their rationale. They're saying "Comparison of =
a known non-null pointer to NULL is probably a bug, so let's produce a =
diagnostic when it happens." I'd have preferred to see a non-fatal=
diagnostic; unfortunately there's no portable way to produce a non-fat=
al diagnostic AFAIK.</div><span class=3D"gmail-"><div>=C2=A0</div><blockquo=
te class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px =
solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gma=
il_extra"><div class=3D"gmail_quote"><span class=3D"gmail-m_-59301052643693=
99928gmail-"><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:=
1ex"><div dir=3D"ltr"><div class=3D"gmail_quote"><div>Now, we could still d=
o something like</div><span class=3D"gmail-m_-5930105264369399928gmail-m_-3=
618923533677495598gmail-"><div><br></div><div><font face=3D"monospace, mono=
space">=C2=A0 =C2=A0 template<typename T></font></div><div><font face=
=3D"monospace, monospace">=C2=A0 =C2=A0 auto GETPOINTER(T&& t) {</f=
ont></div></span><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 if constexpr(is_convertible_v<T&&<wbr>, bool>) {</=
font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 return bool(t) ?=C2=A0</font><span style=3D"font-famil=
y:monospace,monospace">std::addressof(*t) : nullptr;</span></div><div><span=
style=3D"font-family:monospace,monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 }</s=
pan><br></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0=
=C2=A0 return std::addressof(*t);</font></div><div><font face=3D"monospace=
, monospace">=C2=A0 =C2=A0 }</font></div></div></div></blockquote><div>=C2=
=A0<br></div></span><div>That would only work if the behaviour of `GETPOINT=
ER(p)` were undefined for contiguous past-the-end iterators (and I think it=
should be defined).<br></div><span class=3D"gmail-m_-5930105264369399928gm=
ail-"><div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px =
0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div=
dir=3D"ltr"><div class=3D"gmail_quote"><div>Question, mostly whimsical: Wh=
at would you expect to happen if I provided an AlwaysNull<T> type tha=
t was the complementary type to NotNull<T>?=C2=A0 That is,</div><div>=
<br></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 int i =3D =
42;</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 Alwa=
ysNull<int *> an =3D nullptr; // ok</font></div><div><font face=3D"mo=
nospace, monospace">=C2=A0 =C2=A0 AlwaysNull<int *> an2 =3D &i; =
=C2=A0// runtime error</font></div><div><font face=3D"monospace, monospace"=
>=C2=A0 =C2=A0 if (an) { ... } =C2=A0// compile-time error: AlwaysNull<i=
nt *> is not convertible to bool because "<a href=3D"https://github=
..com/dropbox/nn/blob/master/nn.hpp#L93" target=3D"_blank">that would be sil=
ly</a>"</font></div><div><br></div><div>If this happened, would you wa=
nt <font face=3D"monospace, monospace">GETPOINTER(an)</font> to "do th=
e right thing" and return nullptr, or would you want it to have undefi=
ned behavior, or what?</div><span class=3D"gmail-m_-5930105264369399928gmai=
l-m_-3618923533677495598gmail-"></span></div></div></blockquote><div><br></=
div></span><div>It should return a null pointer. It's a bit of a pointl=
ess type though.<br></div></div></div></div></blockquote><div><br></div></s=
pan><div>I agree that AlwaysNull<T> is a bit of a pointless type. ;) =
=C2=A0However, thinking about corner cases can help clarify the problems we=
're talking about. In this case, the problem is that AlwaysNull<T>=
; and NeverNull<T> have exactly the same public interface (same base =
classes, same members, same free functions): they differ only in the abstra=
ct ideas behind them, not in the public interface. So Concepts Lite cannot =
distinguish between them.</div></div></div></div></blockquote><div>=C2=A0<b=
r></div><div>Concepts <br></div><div><br></div><blockquote class=3D"gmail_q=
uote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,2=
04);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><div clas=
s=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px=
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div di=
r=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><span class=
=3D"gmail-m_-5930105264369399928gmail-"><div><br></div><blockquote class=3D=
"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(2=
04,204,204);padding-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_quote"><=
span class=3D"gmail-m_-5930105264369399928gmail-m_-3618923533677495598gmail=
-"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bord=
er-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div =
class=3D"gmail_extra"><div class=3D"gmail_quote"><span class=3D"gmail-m_-59=
30105264369399928gmail-m_-3618923533677495598gmail-m_428563140955204213gmai=
l-"><div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0p=
x 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div d=
ir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote"><div>Now, =
there is still a problem, even in my happy world where all "pointer-li=
ke" types implement <font face=3D"monospace, monospace">operator*</fon=
t>. The problem is that sometimes a pointer can be non-null and <i>still</i=
> not point to an object. [...]</div></div></div></div></blockquote></span>=
</div></div></div></blockquote><div><br></div></span><span class=3D"gmail-"=
><div>I don't see any reason to define the behavior of <font face=3D"mo=
nospace, monospace">GETPOINTER(a.end())</font> given that there flatly <i>i=
s no object</i> at any memory address that could reasonably be associated w=
ith <font face=3D"monospace, monospace">a.end()</font>. If I understand cor=
rectly, we're in agreement that <font face=3D"monospace, monospace">GET=
POINTER(a.end())</font> should be undefined for e.g. <font face=3D"monospac=
e, monospace">std::list<int> a</font>; we're only in disagreement=
about whether it should be defined for std::vector and std::array.</div></=
span></div></div></blockquote><div><br></div></span><span class=3D"gmail-">=
<div>Pointers do not have to point to valid objects. It makes sense that <i=
>all</i> contiguous iterators map to a valid pointer because this mapping i=
s well defined. Making an exception for past-the-end iterators would compli=
cate things enormously. Consider how one might implement GSL's `span` t=
ype:<br></div><div><br></div><div style=3D"margin-left:40px"><span style=3D=
"font-family:monospace,monospace">T* b_ptr;<br></span></div><div style=3D"m=
argin-left:40px"><span style=3D"font-family:monospace,monospace">T* e</span=
><span style=3D"font-family:monospace,monospace"><span style=3D"font-family=
:monospace,monospace">_ptr</span>;<br><br></span></div><div style=3D"margin=
-left:40px"><span style=3D"font-family:monospace,monospace">template <ty=
pename ContiguousIterator><br></span></div><div style=3D"margin-left:40p=
x"><span style=3D"font-family:monospace,monospace">span(ContiguousIterator =
b, ContiguousIterator e) :<br></span></div><div style=3D"margin-left:40px">=
<span style=3D"font-family:monospace,monospace">=C2=A0=C2=A0=C2=A0 b</span>=
<span style=3D"font-family:monospace,monospace"><span style=3D"font-family:=
monospace,monospace">_ptr</span>(get_pointer(b)),<br>=C2=A0=C2=A0=C2=A0 e</=
span><span style=3D"font-family:monospace,monospace"><span style=3D"font-fa=
mily:monospace,monospace">_ptr</span>(get_pointer(e))<br></span></div><div =
style=3D"margin-left:40px"><span style=3D"font-family:monospace,monospace">=
{<br>}</span></div></span></div></div></div></blockquote><div><br></div><di=
v>Okay, that's fair. You've convinced me that <font face=3D"monospa=
ce, monospace">get_pointer(e)</font> should return the past-the-end pointer=
..</div><div><br></div><div><span class=3D"gmail-m_-5930105264369399928gmail=
-m_-3618923533677495598gmail-"><span class=3D"gmail-"><div><font face=3D"mo=
nospace, monospace">=C2=A0 =C2=A0 template<typename T></font></div><d=
iv><font face=3D"monospace, monospace">=C2=A0 =C2=A0 auto <i>GETPOINTER</i>=
(T&& t) {</font></div></span><div><font face=3D"monospace, monospac=
e">=C2=A0 =C2=A0 =C2=A0 =C2=A0 if constexpr(<i>IS_CONTIGUOUS_<wbr>ITERATOR_=
V</i><std::remove_<wbr>reference_t<T>>) {</font></div><div><fon=
t face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 r=
eturn <i>SOME MAGIC INVOLVING A CUSTOMIZATION POINT</i>(t);</font></div><di=
v><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 }</font><=
/div></span><span class=3D"gmail-"><div><font face=3D"monospace, monospace"=
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 if constexpr(is_convertible_v<T&&<w=
br>, bool>) {</font></div><div><font face=3D"monospace, monospace">=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return bool(t) ?=C2=A0</font><span s=
tyle=3D"font-family:monospace,monospace">std::addressof(*t) : nullptr;</spa=
n></div><div><span style=3D"font-family:monospace,monospace">=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 }</span><br></div><div><font face=3D"monospace, monospace">=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 return std::addressof(*t);</font></div><div><fo=
nt face=3D"monospace, monospace">=C2=A0 =C2=A0 }</font></div></span></div><=
div class=3D"gmail_quote"><br></div><div class=3D"gmail_quote">There are at=
least four "proposals" on the table for the text of <i><font fac=
e=3D"monospace, monospace">SOME MAGIC INVOLVING A CUSTOMIZATION POINT</font=
></i>.<br></div><div class=3D"gmail_quote">(A) Nevin Liber's <a href=3D=
"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf" target=
=3D"_blank">N3884</a> proposed (ADL) <font face=3D"monospace, monospace">do=
_pointer_from(t)</font>.</div><div class=3D"gmail_quote">(B) Joseph Thomson=
(you) seem to propose <font face=3D"monospace, monospace">static_cast<T=
*>(t)</font>.</div><div class=3D"gmail_quote">(C) Jonathan Coe's <a =
href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4388.html"=
target=3D"_blank">N4388</a>=C2=A0(propagate_const) seems to propose=C2=A0<=
font face=3D"monospace, monospace">t.get()</font>.</div>(D) Nobody has prop=
osed, but IMHO it should be considered, to just make <font face=3D"monospac=
e, monospace">&*t</font> well-defined somehow, since that's what pe=
ople are doing today in practice.</div><div class=3D"gmail_quote"><br></div=
><div class=3D"gmail_quote"><div class=3D"gmail_quote">(For the text of <fo=
nt face=3D"monospace, monospace"><i>IS_CONTIGUOUS_ITERATOR_V</i></font>, Ne=
vin Liber's <a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/pape=
rs/2014/n3884.pdf" target=3D"_blank">N3884</a> proposed literally=C2=A0<fon=
t face=3D"monospace, monospace"><a href=3D"http://www.open-std.org/jtc1/sc2=
2/wg21/docs/papers/2014/n3884.pdf" target=3D"_blank">is_contiguous_<wbr>ite=
rator_v</a></font>; and someone at the 2014 Issaquah meeting=C2=A0<a href=
=3D"http://wiki.edg.com/bin/view/Wg21issaquah/N3884" target=3D"_blank">[pri=
vate wiki]</a>=C2=A0suggested SFINAE on the existence of (ADL)=C2=A0<font f=
ace=3D"monospace, monospace">do_pointer_from(t)</font>.)</div><div><br></di=
v></div><div class=3D"gmail_quote">On (B), notice that arbitrary contiguous=
iterators aren't necessarily convertible to pointers. This is actually=
listed as a benefit e.g. <a href=3D"http://codereview.stackexchange.com/qu=
estions/113866/the-final-word-on-contiguous-iterators#comment210916_113870"=
target=3D"_blank">here</a> and <a href=3D"http://stackoverflow.com/a/32702=
585/1424877" target=3D"_blank">here</a>. After all, if I wanted a type that=
behaved like <font face=3D"monospace, monospace">T*</font> and <i>was</i> =
implicitly convertible to <font face=3D"monospace, monospace">T*</font>, I =
would just use <font face=3D"monospace, monospace">T*</font>!</div></div></=
div></blockquote><div><br></div><div>If I understand correctly, these are b=
enefits of disallowing <i>implicit</i> conversion (the term "conversio=
n" seems to be implicitly implicit, e.g. `is_convertible`). Explicit c=
onversion AFAIK represents a <i>subversion</i> of the type system, and this=
is what I am suggesting.<br></div><br><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padd=
ing-left:1ex"><div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gma=
il_quote"><div>From the meeting notes, it sounds like a major point of cont=
ention with Nevin's N3884 was that it introduced a customization point,=
and customization points are painful as hell. (See: <font face=3D"monospac=
e, monospace">std::swap</font>.)</div></div></div></div></blockquote><div><=
br><div>Customization points <i>are</i> painful, which is why I'm sugge=
sting explicit conversion to `T*`, which has the potential to work with bot=
h pointers <i>and</i> pointer-like class types.<br></div>=C2=A0</div><block=
quote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1=
px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div class=3D"=
gmail_extra"><div class=3D"gmail_quote"><div>Another (minor?) point of cont=
ention was whether <font face=3D"monospace, monospace">std::pointer_from</f=
ont> should also be defined to work on smart pointers, or <i>just</i> on co=
ntiguous iterators. Nobody seems to have been talking about "pointer-l=
ike types" at that point; the only problem in scope was how the user-p=
rogrammer is supposed to extract a past-the-end pointer from a past-the-end=
contiguous iterator without invoking UB. (And this problem does not seem t=
o have been solved, as of C++17.)</div></div></div></div></blockquote><div>=
<br></div><div>`propagate_const` is one use case for supporting all pointer=
-like types. There are probably others I haven't thought of.<br></div><=
div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><blockquote=
class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px so=
lid rgb(204,204,204);padding-left:1ex"><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padd=
ing-left:1ex">I definitely would not expect static_cast<T*>(p) to wor=
k; for example it doesn't work for std::shared_ptr or std::unique_ptr, =
which IMNSHO certainly ought to be considered "pointer-like types"=
;.<br></blockquote><br>Explicit conversion to `T*` would be added for these=
types, and any other types that want to meet the requirements for PointerL=
ike.<br></blockquote><br>That's a non-starter. Getting a raw unmanaged =
pointer out of a managed pointer is deliberately not something you can do w=
ith type conversions; it deliberately requires extra typing. (Not to mentio=
n, it would break existing code to add such a conversion, even as an explic=
it conversion. Explicit conversions are relevant to SFINAE.)<span class=3D"=
gmail-"></span></blockquote><div>=C2=A0<br></div><div>As I mentioned above,=
it's my understanding that <i>explicit</i> conversion represents a sub=
version of the type system, and is not something people are likely to do by=
accident. In fact, IMO this:<br><br></div><div><div style=3D"margin-left:4=
0px"><span style=3D"font-family:monospace,monospace">auto p =3D static_cast=
<T*>(smart_pointer);</span><br></div><br></div><div>Is more explicit =
than this:<br></div><div style=3D"margin-left:40px"><br></div><div style=3D=
"margin-left:40px"><span style=3D"font-family:monospace,monospace">auto p =
=3D smart_pointer.get();</span><br></div><div><br></div><div>A `static_cast=
` is both more typing <i>and</i> it requires explicit specification of the =
pointer type.<br></div><div><br>But I agree that if it breaks a not-insigni=
ficant amount of code then it's a non-starter (which would be a shame).=
Would be helpful to have an example though.<br></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/CAHocnE9BG%2BuceUxfy%3DcsFUcRm06u6LPd=
XTAcmWE9MHQSUeS_wA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter"=
>https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHocnE9BG%2B=
uceUxfy%3DcsFUcRm06u6LPdXTAcmWE9MHQSUeS_wA%40mail.gmail.com</a>.<br />
--94eb2c1b45d28855c005489b1777--
.
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Fri, 17 Feb 2017 08:37:02 +0100
Raw View
Le 31/01/2017 =C3=A0 15:26, joseph.thomson@gmail.com a =C3=A9crit :
> There is currently no uniform way to retrieve a pointer from an arbitrary=
pointer or pointer-like object. One real example where such a feature woul=
d be useful is the proposed `propagate_const` wrapper, which currently requ=
ires compatible class types to have a `get` member function. This is an int=
rusive requirement, that the user may not even have the capacity to meet.
>
> I propose adding a `get_pointer` free function to mirror the `get` member=
functions present in many pointer-like types, much like how the `begin` an=
d `end` free functions mirror the corresponding member functions present in=
many range types. The default `get_pointer` implementation would look some=
thing like this:
>
> template <typename T>
> auto get_pointer (T const& t) {
> using element_type =3D pointer_traits<T>::element_type;
> return static_cast<element_type*>(t);
> }
>
> This will work for `T*` and any pointer-like type that provides implicit =
or explicit conversion to `element_type*` (such as the proposed `observer_p=
tr`). I suggest casting be the default implementation because providing an =
explicit conversion operator seems like a much more natural way to allow co=
nversion of pointer-like types to pointers than with an arbitrarily named f=
unction like `get`. I suggest that an explicit conversion operator be added=
to the standard library smart pointers, `unique_ptr` and `shared_ptr`. Typ=
es that cannot be converted to `element_type*` can provide a `get_pointer` =
free function within the same namespace that can be found via ADL.
>
> Thoughts?
>
I'll be for extending the pointer-like requirements to a customizable=20
get_pointer, if e.g. propagate_const could be implemented in a easier way.
How to customize get_pointer is a different issue (I know that today we=20
are usually customizing via ADL, but not always, e.g. executors).
What will be wrong adding a get_pointer static function in pointer_traits?
If we have a default, I don't believe it is worth defaulting get_pointer=20
to other expression than ptr.get(), so that we don't need to change=20
anything.
get_pointer must of course be specialized for T*.
Vicente
--=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/4ec48ebe-f21c-67d4-2769-e08cd211bb69%40wanadoo.f=
r.
.
Author: joseph.thomson@gmail.com
Date: Fri, 17 Feb 2017 01:29:12 -0800 (PST)
Raw View
------=_Part_472_913426777.1487323752773
Content-Type: multipart/alternative;
boundary="----=_Part_473_173260677.1487323752773"
------=_Part_473_173260677.1487323752773
Content-Type: text/plain; charset=UTF-8
>
> I'll be for extending the pointer-like requirements to a customizable
> get_pointer, if e.g. propagate_const could be implemented in a easier way.
>
Not so much easier to implement, as to have less intrusive requirements
(e.g. presence of `get` member function).
How to customize get_pointer is a different issue (I know that today we
> are usually customizing via ADL, but not always, e.g. executors).
> What will be wrong adding a get_pointer static function in pointer_traits?
>
That would require the pointer type to be explicitly specified (e.g.
`pointer_traits<unique_ptr<T>>::get_pointer(p)`). Also, this doesn't solve
the problem of the customization point (unless you want to encourage
specialization of the entire `pointer_traits` structure just to customize
`get_pointer`).
> If we have a default, I don't believe it is worth defaulting get_pointer
> to other expression than ptr.get(), so that we don't need to change
> anything.
>
`get_pointer(p)` could use `p.get()` if it exists and returns the correct
type, and if not fall back to explicit conversion.
get_pointer must of course be specialized for T*.
>
Not with the implementation I just suggested.
--
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/cc041f25-2883-4377-a382-31f68492388f%40isocpp.org.
------=_Part_473_173260677.1487323752773
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">I'll be f=
or extending the pointer-like requirements to a customizable=20
<br>get_pointer, if e.g. propagate_const could be implemented in a easier w=
ay.
<br>
</blockquote><div>=C2=A0 <br>Not so much easier to implement, as to have le=
ss intrusive requirements (e.g. presence of `get` member function).<br><br>=
</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8=
ex;border-left: 1px #ccc solid;padding-left: 1ex;">How to customize get_poi=
nter is a different issue (I know that today we=20
<br>are usually customizing via ADL, but not always, e.g. executors).
<br>What will be wrong adding a get_pointer static function in pointer_trai=
ts?
<br></blockquote><div><br>=C2=A0That would require the pointer type to be e=
xplicitly specified (e.g. <span style=3D"font-family: courier new,monospace=
;">`pointer_traits<unique_ptr<T>>::get_pointer(p)`</span>). Als=
o, this doesn't solve the problem of the customization point (unless yo=
u want to encourage specialization of the entire <span style=3D"font-family=
: courier new,monospace;">`pointer_traits`</span> structure just to customi=
ze <span style=3D"font-family: courier new,monospace;">`get_pointer`</span>=
).<br></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"mar=
gin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">I=
f we have a default, I don't believe it is worth defaulting get_pointer=
=20
<br>to other expression than ptr.get(), so that we don't need to change=
=20
<br>anything.
<br></blockquote><div>=C2=A0<br><span style=3D"font-family: courier new,mon=
ospace;">`get_pointer(p)`</span> could use <span style=3D"font-family: cour=
ier new,monospace;">`p.get()`</span> if it exists and returns the correct t=
ype, and if not fall back to explicit conversion.<br><br></div><blockquote =
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1p=
x #ccc solid;padding-left: 1ex;">get_pointer must of course be specialized =
for T*.
<br></blockquote><div><br>Not with the implementation I just suggested.<br>=
</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/cc041f25-2883-4377-a382-31f68492388f%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/cc041f25-2883-4377-a382-31f68492388f=
%40isocpp.org</a>.<br />
------=_Part_473_173260677.1487323752773--
------=_Part_472_913426777.1487323752773--
.
Author: "Arthur O'Dwyer" <arthur.j.odwyer@gmail.com>
Date: Fri, 17 Feb 2017 18:36:33 -0800
Raw View
--001a11444b520df90b0548c4e6bb
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Fri, Feb 17, 2017 at 1:29 AM, <joseph.thomson@gmail.com> wrote:
> I'll be for extending the pointer-like requirements to a customizable
>> get_pointer, if e.g. propagate_const could be implemented in a easier
>> way.
>>
>
> Not so much easier to implement, as to have less intrusive requirements
> (e.g. presence of `get` member function).
>
> How to customize get_pointer is a different issue (I know that today we
>> are usually customizing via ADL, but not always, e.g. executors).
>> What will be wrong adding a get_pointer static function in
>> pointer_traits?
>>
>
> That would require the pointer type to be explicitly specified (e.g.
> `pointer_traits<unique_ptr<T>>::get_pointer(p)`). Also, this doesn't
> solve the problem of the customization point (unless you want to encourag=
e
> specialization of the entire `pointer_traits` structure just to customize
> `get_pointer`).
>
Another (bigger IMHO) problem with using anything out of pointer_traits is
that the standard library currently does not provide any specializations of
pointer_traits for many relevant "pointer-like" types, including
ContiguousIterator types which was the problem Joseph was originally trying
to solve.
For example, on both libstdc++ and libc++,
std::pointer_traits<std::vector<int>::iterator>::element_type
is (int*) <http://melpon.org/wandbox/permlink/2ko1TIEfePmxwcok>, not (int).
I don't know how they come up with that exactly, but it's clearly not what
one would expect based on decltype(*iterator).
I do see that the section defining pointer_traits uses the exact phrase
"pointer-like types" without defining it. Maybe defining "pointer-like"
would be a good first step? ;)
=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/CADvuK0KB1PoHbNwv9V8fdAspp%3DtxOYpBkgGeRVCR4RJnw=
n934g%40mail.gmail.com.
--001a11444b520df90b0548c4e6bb
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Fri, Feb 17, 2017 at 1:29 AM, <span dir=3D"ltr"><<a=
href=3D"mailto:joseph.thomson@gmail.com" target=3D"_blank">joseph.thomson@=
gmail.com</a>></span> wrote:<br><div class=3D"gmail_extra"><div class=3D=
"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left=
-style:solid;padding-left:1ex"><div dir=3D"ltr"><span class=3D"gmail-"><blo=
ckquote 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;paddi=
ng-left:1ex">I'll be for extending the pointer-like requirements to a c=
ustomizable=20
<br>get_pointer, if e.g. propagate_const could be implemented in a easier w=
ay.
<br>
</blockquote></span><div>=C2=A0 <br>Not so much easier to implement, as to =
have less intrusive requirements (e.g. presence of `get` member function).<=
br><br></div><span class=3D"gmail-"><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">How to customize get_p=
ointer is a different issue (I know that today we=20
<br>are usually customizing via ADL, but not always, e.g. executors).
<br>What will be wrong adding a get_pointer static function in pointer_trai=
ts?
<br></blockquote></span><div><br>=C2=A0That would require the pointer type =
to be explicitly specified (e.g. <span style=3D"font-family:'courier ne=
w',monospace">`pointer_traits<unique_ptr<T>><wbr>::get_poin=
ter(p)`</span>). Also, this doesn't solve the problem of the customizat=
ion point (unless you want to encourage specialization of the entire <span =
style=3D"font-family:'courier new',monospace">`pointer_traits`</spa=
n> structure just to customize <span style=3D"font-family:'courier new&=
#39;,monospace">`get_pointer`</span>).<br></div></div></blockquote><div><br=
></div><div>Another (bigger IMHO) problem with using anything out of pointe=
r_traits is that the standard library currently does not provide any specia=
lizations of pointer_traits for many relevant "pointer-like" type=
s, including ContiguousIterator types which was the problem Joseph was orig=
inally trying to solve.</div><div><br></div><div>For example, on both libst=
dc++ and libc++,</div><div>=C2=A0 =C2=A0 std::pointer_traits<std::vector=
<int>::iterator>::element_type<br></div><div><a href=3D"http://mel=
pon.org/wandbox/permlink/2ko1TIEfePmxwcok">is (int*)</a>, not (int). I don&=
#39;t know how they come up with that exactly, but it's clearly not wha=
t one would expect based on decltype(*iterator).</div><div><br></div><div>I=
do see that the section defining pointer_traits uses the exact phrase &quo=
t;pointer-like types" without defining it. Maybe defining "pointe=
r-like" would be a good first step? ;)</div><div><br></div><div>=E2=80=
=93Arthur</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/CADvuK0KB1PoHbNwv9V8fdAspp%3DtxOYpBkg=
GeRVCR4RJnwn934g%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0KB1PoHbN=
wv9V8fdAspp%3DtxOYpBkgGeRVCR4RJnwn934g%40mail.gmail.com</a>.<br />
--001a11444b520df90b0548c4e6bb--
.
Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
Date: Sat, 18 Feb 2017 12:57:03 -0800 (PST)
Raw View
------=_Part_2781_2012016282.1487451423475
Content-Type: multipart/alternative;
boundary="----=_Part_2782_1350147942.1487451423476"
------=_Part_2782_1350147942.1487451423476
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Friday, February 17, 2017 at 6:36:36 PM UTC-8, Arthur O'Dwyer wrote:
>
> On Fri, Feb 17, 2017 at 1:29 AM, <joseph.thomson@gmail.com> wrote:
>
>> How to customize get_pointer is a different issue (I know that today we=
=20
>>>
>> are usually customizing via ADL, but not always, e.g. executors).=20
>>> What will be wrong adding a get_pointer static function in=20
>>> pointer_traits?=20
>>>
>>
>> That would require the pointer type to be explicitly specified (e.g.=20
>> `pointer_traits<unique_ptr<T>>::get_pointer(p)`). Also, this doesn't=20
>> solve the problem of the customization point (unless you want to encoura=
ge=20
>> specialization of the entire `pointer_traits` structure just to=20
>> customize `get_pointer`).
>>
>
> Another (bigger IMHO) problem with using anything out of pointer_traits i=
s=20
> that the standard library currently does not provide any specializations =
of=20
> pointer_traits for many relevant "pointer-like" types, including=20
> ContiguousIterator types which was the problem Joseph was originally tryi=
ng=20
> to solve.
>
> For example, on both libstdc++ and libc++,
> std::pointer_traits<std::vector<int>::iterator>::element_type
> is (int*) <http://melpon.org/wandbox/permlink/2ko1TIEfePmxwcok>, not=20
> (int). I don't know how they come up with that exactly, but it's clearly=
=20
> not what one would expect based on decltype(*iterator).
>
I have just filed a bug report against libc++ on this subject.
https://bugs.llvm.org/show_bug.cgi?id=3D32006
libc++ actually already attempts to provide a non-standard extension
auto *p =3D std::__to_raw_pointer(ptrlike);
but it doesn't work for std::vector<int>::iterator because of this=20
pointer_traits issue.
=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/7996cda8-fc75-48dd-be8f-f874810f8395%40isocpp.or=
g.
------=_Part_2782_1350147942.1487451423476
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Friday, February 17, 2017 at 6:36:36 PM UTC-8, Arthur O=
'Dwyer wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"l=
tr">On Fri, Feb 17, 2017 at 1:29 AM, <span dir=3D"ltr"><<a href=3D"mail=
to:joseph.thomson@gmail.com" target=3D"_blank" rel=3D"nofollow" onmousedown=
=3D"this.href=3D'mailto:joseph.thomson@gmail.com';return true;" onc=
lick=3D"this.href=3D'mailto:joseph.thomson@gmail.com';return true;"=
>joseph.thomson@gmail.com</a>></span> wrote:<br><div><div class=3D"gmail=
_quote"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex=
;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style=
:solid;padding-left:1ex"><div dir=3D"ltr"><span><blockquote class=3D"gmail_=
quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-=
color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">How to cus=
tomize get_pointer is a different issue (I know that today we=C2=A0<br></bl=
ockquote></span><span><blockquote class=3D"gmail_quote" style=3D"margin:0px=
0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);bor=
der-left-style:solid;padding-left:1ex">are usually customizing via ADL, but=
not always, e.g. executors).
<br>What will be wrong adding a get_pointer static function in pointer_trai=
ts?
<br></blockquote></span><div><br>=C2=A0That would require the pointer type =
to be explicitly specified (e.g. <span style=3D"font-family:'courier ne=
w',monospace">`pointer_traits<unique_ptr<T>><wbr>::get_poin=
ter(p)`</span>). Also, this doesn't solve the problem of the customizat=
ion point (unless you want to encourage specialization of the entire <span =
style=3D"font-family:'courier new',monospace">`pointer_traits`</spa=
n> structure just to customize <span style=3D"font-family:'courier new&=
#39;,monospace">`get_pointer`</span>).<br></div></div></blockquote><div><br=
></div><div>Another (bigger IMHO) problem with using anything out of pointe=
r_traits is that the standard library currently does not provide any specia=
lizations of pointer_traits for many relevant "pointer-like" type=
s, including ContiguousIterator types which was the problem Joseph was orig=
inally trying to solve.</div><div><br></div><div>For example, on both libst=
dc++ and libc++,</div><div>=C2=A0 =C2=A0 std::pointer_traits<std::<wbr>v=
ector<int>::iterator>::<wbr>element_type<br></div><div><a href=3D"=
http://melpon.org/wandbox/permlink/2ko1TIEfePmxwcok" target=3D"_blank" rel=
=3D"nofollow" onmousedown=3D"this.href=3D'http://www.google.com/url?q\x=
3dhttp%3A%2F%2Fmelpon.org%2Fwandbox%2Fpermlink%2F2ko1TIEfePmxwcok\x26sa\x3d=
D\x26sntz\x3d1\x26usg\x3dAFQjCNHnuZ3Sm57AGfi9KRnolB6qFpznag';return tru=
e;" onclick=3D"this.href=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2=
Fmelpon.org%2Fwandbox%2Fpermlink%2F2ko1TIEfePmxwcok\x26sa\x3dD\x26sntz\x3d1=
\x26usg\x3dAFQjCNHnuZ3Sm57AGfi9KRnolB6qFpznag';return true;">is (int*)<=
/a>, not (int). I don't know how they come up with that exactly, but it=
's clearly not what one would expect based on decltype(*iterator).</div=
></div></div></div></blockquote><div><br></div><div>I have just filed a bug=
report against libc++ on this subject.</div><div><a href=3D"https://bugs.l=
lvm.org/show_bug.cgi?id=3D32006">https://bugs.llvm.org/show_bug.cgi?id=3D32=
006</a><br></div><div><br></div><div>libc++ actually already attempts to pr=
ovide a non-standard extension</div><div>=C2=A0 =C2=A0 <font face=3D"courie=
r new, monospace">auto *p =3D std::__to_raw_pointer(ptrlike);</font></div><=
div>but it doesn't work for <font face=3D"courier new, monospace">std::=
vector<int>::iterator</font> because of this pointer_traits issue.</d=
iv><div><br></div><div>=E2=80=93Arthur</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/7996cda8-fc75-48dd-be8f-f874810f8395%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/7996cda8-fc75-48dd-be8f-f874810f8395=
%40isocpp.org</a>.<br />
------=_Part_2782_1350147942.1487451423476--
------=_Part_2781_2012016282.1487451423475--
.
Author: Joseph Thomson <joseph.thomson@gmail.com>
Date: Sun, 19 Feb 2017 21:23:34 +0800
Raw View
--94eb2c1b45d2d71c060548e20d18
Content-Type: text/plain; charset=UTF-8
On 19 Feb 2017 4:57 a.m., "Arthur O'Dwyer" <arthur.j.odwyer@gmail.com>
wrote:
On Friday, February 17, 2017 at 6:36:36 PM UTC-8, Arthur O'Dwyer wrote:
> On Fri, Feb 17, 2017 at 1:29 AM, <joseph.thomson@gmail.com> wrote:
>
>> How to customize get_pointer is a different issue (I know that today we
>>>
>> are usually customizing via ADL, but not always, e.g. executors).
>>> What will be wrong adding a get_pointer static function in
>>> pointer_traits?
>>>
>>
>> That would require the pointer type to be explicitly specified (e.g.
>> `pointer_traits<unique_ptr<T>>::get_pointer(p)`). Also, this doesn't
>> solve the problem of the customization point (unless you want to encourage
>> specialization of the entire `pointer_traits` structure just to
>> customize `get_pointer`).
>>
>
> Another (bigger IMHO) problem with using anything out of pointer_traits is
> that the standard library currently does not provide any specializations of
> pointer_traits for many relevant "pointer-like" types, including
> ContiguousIterator types which was the problem Joseph was originally trying
> to solve.
>
> For example, on both libstdc++ and libc++,
> std::pointer_traits<std::vector<int>::iterator>::element_type
> is (int*) <http://melpon.org/wandbox/permlink/2ko1TIEfePmxwcok>, not
> (int). I don't know how they come up with that exactly, but it's clearly
> not what one would expect based on decltype(*iterator).
>
I have just filed a bug report against libc++ on this subject.
https://bugs.llvm.org/show_bug.cgi?id=32006
libc++ actually already attempts to provide a non-standard extension
auto *p = std::__to_raw_pointer(ptrlike);
but it doesn't work for std::vector<int>::iterator because of this
pointer_traits issue.
The description of `pointer_traits` says that it uses `T::element_type` or
the first template parameter if it doesn't exist.
http://en.cppreference.com/w/cpp/iterator/iterator_traits
The first template parameter for whatever class libstdc++ defines
`vector<T>::iterator` to be is probably `T*`. Essentially, it isn't a
pointer-like type as far as `pointer_traits` is concerned. I don't think
this is a violation of the standard, as random access iterators do not need
to define `element_type`. If iterators were to fall under a PointerLike
concept, the definition would have to be changed.
--
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/CAHocnE_eksDGDWEXfz9BLF7xnVqjM63273j4L98GN-29%3DNDxeQ%40mail.gmail.com.
--94eb2c1b45d2d71c060548e20d18
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"auto"><div class=3D"gmail_extra" dir=3D"auto"><div class=3D"gma=
il_quote">On 19 Feb 2017 4:57 a.m., "Arthur O'Dwyer" <<a h=
ref=3D"mailto:arthur.j.odwyer@gmail.com">arthur.j.odwyer@gmail.com</a>> =
wrote:<br type=3D"attribution"><blockquote class=3D"quote" style=3D"margin:=
0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><d=
iv class=3D"quoted-text">On Friday, February 17, 2017 at 6:36:36 PM UTC-8, =
Arthur O'Dwyer wrote:</div><blockquote class=3D"gmail_quote" style=3D"m=
argin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div=
dir=3D"ltr"><div class=3D"quoted-text">On Fri, Feb 17, 2017 at 1:29 AM, <=
span dir=3D"ltr"><<a href=3D"mailto:joseph.thomson@gmail.com" rel=3D"nof=
ollow" target=3D"_blank">joseph.thomson@gmail.com</a>></span> wrote:<br>=
</div><div class=3D"quoted-text"><div><div class=3D"gmail_quote"><blockquot=
e 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-lef=
t:1ex"><div dir=3D"ltr"><span><blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,=
204);border-left-style:solid;padding-left:1ex">How to customize get_pointer=
is a different issue (I know that today we=C2=A0<br></blockquote></span><s=
pan><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bor=
der-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:sol=
id;padding-left:1ex">are usually customizing via ADL, but not always, e.g. =
executors).
<br>What will be wrong adding a get_pointer static function in pointer_trai=
ts?
<br></blockquote></span><div><br>=C2=A0That would require the pointer type =
to be explicitly specified (e.g. <span style=3D"font-family:'courier ne=
w',monospace">`pointer_traits<unique_ptr<T>><wbr>::get_poin=
ter(p)`</span>). Also, this doesn't solve the problem of the customizat=
ion point (unless you want to encourage specialization of the entire <span =
style=3D"font-family:'courier new',monospace">`pointer_traits`</spa=
n> structure just to customize <span style=3D"font-family:'courier new&=
#39;,monospace">`get_pointer`</span>).<br></div></div></blockquote><div><br=
></div><div>Another (bigger IMHO) problem with using anything out of pointe=
r_traits is that the standard library currently does not provide any specia=
lizations of pointer_traits for many relevant "pointer-like" type=
s, including ContiguousIterator types which was the problem Joseph was orig=
inally trying to solve.</div><div><br></div><div>For example, on both libst=
dc++ and libc++,</div><div>=C2=A0 =C2=A0 std::pointer_traits<std::vecto<=
wbr>r<int>::iterator>::element_<wbr>type<br></div><div><a href=3D"=
http://melpon.org/wandbox/permlink/2ko1TIEfePmxwcok" rel=3D"nofollow" targe=
t=3D"_blank">is (int*)</a>, not (int). I don't know how they come up wi=
th that exactly, but it's clearly not what one would expect based on de=
cltype(*iterator).</div></div></div></div></div></blockquote><div><br></div=
><div>I have just filed a bug report against libc++ on this subject.</div><=
div><a href=3D"https://bugs.llvm.org/show_bug.cgi?id=3D32006" target=3D"_bl=
ank">https://bugs.llvm.org/show_<wbr>bug.cgi?id=3D32006</a><br></div><div><=
br></div><div>libc++ actually already attempts to provide a non-standard ex=
tension</div><div>=C2=A0 =C2=A0 <font face=3D"courier new, monospace">auto =
*p =3D std::__to_raw_pointer(ptrlike)<wbr>;</font></div><div>but it doesn&#=
39;t work for <font face=3D"courier new, monospace">std::vector<int>:=
:iterator</font> because of this pointer_traits issue.</div></div></blockqu=
ote></div></div><div dir=3D"auto"><span style=3D"font-family:sans-serif"><b=
r></span></div><div dir=3D"auto"><span style=3D"font-family:sans-serif">The=
description of `pointer_traits` says that it uses `T::element_type` or the=
first template parameter if it doesn't exist.</span></div><div dir=3D"=
auto"><br></div><div dir=3D"auto"><a href=3D"http://en.cppreference.com/w/c=
pp/iterator/iterator_traits">http://en.cppreference.com/w/cpp/iterator/iter=
ator_traits</a></div><div dir=3D"auto"><span style=3D"font-family:sans-seri=
f"><br></span></div><div dir=3D"auto"><span style=3D"font-family:sans-serif=
">The first template parameter for whatever class libstdc++ defines `vector=
<T>::iterator` to be is probably `T*`. Essentially, it isn't a po=
inter-like type as far as `pointer_traits` is concerned. I don't think =
this is a violation of the standard, as random access iterators do not need=
to define `element_type`. If iterators were to fall under a PointerLike co=
ncept, the definition would have to be changed.</span><br></div><div dir=3D=
"auto"><br></div><div class=3D"gmail_extra" dir=3D"auto"></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/CAHocnE_eksDGDWEXfz9BLF7xnVqjM63273j4=
L98GN-29%3DNDxeQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAHocnE_eksDGDW=
EXfz9BLF7xnVqjM63273j4L98GN-29%3DNDxeQ%40mail.gmail.com</a>.<br />
--94eb2c1b45d2d71c060548e20d18--
.