Topic: Make standard Tuple interface extensible to user
Author: Tomasz <tomaszkam@gmail.com>
Date: Sat, 8 Aug 2015 23:33:06 -0700 (PDT)
Raw View
------=_Part_3129_320339649.1439101986302
Content-Type: multipart/alternative;
boundary="----=_Part_3130_1853263124.1439101986302"
------=_Part_3130_1853263124.1439101986302
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Currently, the standard interface for tuple-like types, consists of tree=20
members:
- trait std::tuple_size<T>=20
- trait std::tuple_element<I, T>=20
- function template std::get<I>(T)
If I am writing my own tuple_like type, for e.g. compressed_type and I want=
=20
it to behave as a standard tuple, I would need to do following:
- specialize tuple_size
- specialize tuple_element
- add new overload for std::get
The first two items are fine, but third one seems to be no-go. The standard=
=20
prohibit extension of the std namespace with new overloads, so I cannot add=
=20
overload of get for compressed pair (function template cannot be partially=
=20
specialized). Furthermore, the standard solution to declare the get method=
=20
in my class namsepace and use ADL will not work, because ADL is not invoked=
=20
for function template class with explicitly provided argument (index).
To resolve the problem I propose that std::get<I>(t) definition should be=
=20
changed to invoke tuple_get(std::integral_constant<std::size_t, I>{}, t),=
=20
where tuple_get is defined as customization point, i.e. std::get is=20
required to find of overload tuple_get via ADL. The benefits of the=20
solution:
1. It makes the tuple-like interface extensible for user defined classes -=
=20
to make class a tuple I need to specialize tuple_size, tuple_element and=20
provide tuple_get overload in my own namespace. Instead of passing index as=
=20
non-type template argument, it is passed used integral_constant argument to=
=20
allows use of ADL.
2. It makes the implementation of tuple-interface easier. Instead of=20
writing the SFINAEd overload for index zero and non zero:
template<std::size_t I, typename T>
enable_if_t<I =3D=3D 0, tuple_element_t<I, decay_t<I>>> const& get(T const&=
t);
template<std::size_t I, typename T>
enable_if_t<I !=3D 0, tuple_element_t<I, decay_t<I>>> const& get(T const& t=
);
I can just rely on the partial template ordering.
tuple_element_t<0, decay_t<I>> const&=20
tuple_get(integral_constant<std::size_t, 0>, T const&);
//Zero case, will be used as more specialzied
template<std::size_t I, typename T>
tuple_element_t<I, decay_t<I>> const&=20
tuple_get(integral_constant<std::size_t, I>, T const&)
3. The type access for the tuple should be implemented using the tuple=20
interface (tuple_size_t, tuple_element_t, tuple_get), so it will be=20
automatically provided for any user-defined class that meats tuple=20
requirements.
template<typename T, typename Tuple, typename =3D enable_if_t<only_one<T,=
=20
std::decay_t<Tuple>>::value>>
T const& get(Tuple const&) { return tuple_get(index_of<T,=20
std::decay_t<Tuple>>{}, t); }
only_one<T, std::decay_tuple_t<tuple>>::value is expected to return true if=
=20
there is only one occurrence of type T in tuple, index_of returns first=20
index of type T (in form of integral_consant<std::size_t, I>). Both can=20
rely on use of only tuple_element and tuple_size traits.
Regards,
Tomasz Kami=C5=84ski
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
------=_Part_3130_1853263124.1439101986302
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Currently, the standard interface for tuple-like types, co=
nsists of tree members:<br>=C2=A0 - trait std::tuple_size<T> <br>=C2=
=A0 - trait std::tuple_element<I, T> <br>=C2=A0 - function template s=
td::get<I>(T)<br>If I am writing my own tuple_like type, for e.g. com=
pressed_type and I want it to behave as a standard tuple, I would need to d=
o following:<br>=C2=A0 - specialize tuple_size<br>=C2=A0 - specialize tuple=
_element<br>=C2=A0 - add new overload for std::get<br>The first two items a=
re fine, but third one seems to be no-go. The standard prohibit extension o=
f the std namespace with new overloads, so I cannot add overload of get for=
compressed pair (function template cannot be partially specialized). Furth=
ermore, the standard solution to declare the get method in my class namsepa=
ce and use ADL will not work, because ADL is not invoked for function templ=
ate class with explicitly provided argument (index).<br><br>To resolve the =
problem I propose that std::get<I>(t) definition should be changed to=
invoke tuple_get(std::integral_constant<std::size_t, I>{}, t), where=
tuple_get is defined as customization point, i.e. std::get is required to =
find of overload tuple_get via ADL. The benefits of the solution:<br><br>1.=
It makes the tuple-like interface extensible for user defined classes - to=
make class a tuple I need to specialize tuple_size, tuple_element and prov=
ide tuple_get overload in my own namespace. Instead of passing index as non=
-type template argument, it is passed used integral_constant argument to al=
lows use of ADL.<br><br>2. It makes the implementation of tuple-interface e=
asier. Instead of writing the SFINAEd overload for index zero and non zero:=
<br><span style=3D"font-family: courier new,monospace;">template<std::si=
ze_t I, typename T><br>enable_if_t<I =3D=3D 0, tuple_element_t<I, =
decay_t<I>>> const& get(T const& t);<br><br>template<=
;std::size_t I, typename T><br>enable_if_t<I !=3D 0, tuple_element_t&=
lt;I, decay_t<I>>> const& get(T const& t);</span><br>I =
can just rely on the partial template ordering.<br><span style=3D"font-fami=
ly: courier new,monospace;">tuple_element_t<0, decay_t<I>> cons=
t& tuple_get(integral_constant<std::size_t, 0>, T const&);</s=
pan><br><span style=3D"font-family: courier new,monospace;">//Zero case, wi=
ll be used as more specialzied<br></span><br><span style=3D"font-family: co=
urier new,monospace;">template<std::size_t I, typename T></span><br><=
span style=3D"font-family: courier new,monospace;">tuple_element_t<I, de=
cay_t<I>> const& tuple_get(integral_constant<std::size_t, I=
>, T const&)</span><br><br>3. The type access for the tuple should b=
e implemented using the tuple interface (tuple_size_t, tuple_element_t, tup=
le_get), so it will be automatically provided for any user-defined class th=
at meats tuple requirements.<br><span style=3D"font-family: courier new,mon=
ospace;">template<typename T, typename Tuple, typename =3D enable_if_t&l=
t;only_one<T, std::decay_t<Tuple>>::value>><br>T const&am=
p; get(Tuple const&) { return tuple_get(index_of<T, std::decay_t<=
Tuple>>{}, t); }<br></span>only_one<T, std::decay_tuple_t<tuple=
>>::value is expected to return true if there is only one occurrence =
of type T in tuple, index_of returns first index of type T (in form of inte=
gral_consant<std::size_t, I>). Both can rely on use of only tuple_ele=
ment and tuple_size traits.<br><br>Regards,<br>Tomasz Kami=C5=84ski<br></di=
v>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_3130_1853263124.1439101986302--
------=_Part_3129_320339649.1439101986302--
.
Author: David Krauss <potswa@gmail.com>
Date: Sun, 9 Aug 2015 19:04:11 +0800
Raw View
--Apple-Mail=_8844A2F2-FFFA-47B8-8540-F39DEF04BB6C
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8
> On 2015=E2=80=9308=E2=80=9309, at 2:33 PM, Tomasz <tomaszkam@gmail.com> w=
rote:
>=20
> The first two items are fine, but third one seems to be no-go. The standa=
rd prohibit extension of the std namespace with new overloads, so I cannot =
add overload of get for compressed pair (function template cannot be partia=
lly specialized). Furthermore, the standard solution to declare the get met=
hod in my class namsepace and use ADL will not work, because ADL is not inv=
oked for function template class with explicitly provided argument (index).
ADL is invoked, as long as a template declaration is visible.
namespace my_project {
template< typename >
void get() =3D delete;
std::tuple< int > blah;
int q =3D get< 0 >( blah );
}
http://coliru.stacked-crooked.com/a/09441b3bf7b97111 <http://coliru.stacked=
-crooked.com/a/09441b3bf7b97111>
The problem is that it=E2=80=99s not idiomatic to call get without namespac=
e qualification.
I think this is just one aspect of the more general problem with ADL and id=
iomatically writing std:: which applies to many free functions. There has b=
een discussion here with various solutions such as introducing namespace ad=
l. It occurs to me that std::swap, std::get, std::static_pointer_cast, etc =
could be defined to use ADL. This solves the problem at least up to having =
a common template signature =E2=80=94 there=E2=80=99s no way to call std::g=
et<index>(obj) and still pass a non-type index argument of user-defined typ=
e.
One possible implementation:
// Helper; could be folded into members of tuple, pair, and array.
template< typename >
struct __is_tuple_like : false_type {};
template< typename ... t >
struct __is_tuple_like< tuple< t ... > > : true_type {};
// Stop ADL from causing infinite template recursion.
template< bool >
struct __get_lookup;
template<>
struct __get_lookup< false > {
template< size_t i, typename t >
using result_type =3D decltype( get< i >( declval< t >() ) );
};
// Overload enables std::get syntax to find user's ADL.
template< size_t i, typename t >
typename __get_lookup< __is_tuple_like< decay_t< t > >::value >::template r=
esult_type< i, t >
get( t && o )
{ return get< i >( forward< t >( o ) ); }
http://coliru.stacked-crooked.com/a/9700092ffab74633 <http://coliru.stacked=
-crooked.com/a/9700092ffab74633>
Repeat this pattern for anything else with a generic-ish free function inte=
rface.
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
--Apple-Mail=_8844A2F2-FFFA-47B8-8540-F39DEF04BB6C
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8
<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dutf-8"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-mode: s=
pace; -webkit-line-break: after-white-space;" class=3D""><br class=3D""><di=
v><blockquote type=3D"cite" class=3D""><div class=3D"">On 2015=E2=80=9308=
=E2=80=9309, at 2:33 PM, Tomasz <<a href=3D"mailto:tomaszkam@gmail.com" =
class=3D"">tomaszkam@gmail.com</a>> wrote:</div><br class=3D"Apple-inter=
change-newline"><div class=3D""><span style=3D"font-family: Helvetica; font=
-size: 12px; font-style: normal; font-variant: normal; font-weight: normal;=
letter-spacing: normal; line-height: normal; orphans: auto; text-align: st=
art; text-indent: 0px; text-transform: none; white-space: normal; widows: a=
uto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; displa=
y: inline !important;" class=3D"">The first two items are fine, but third o=
ne seems to be no-go. The standard prohibit extension of the std namespace =
with new overloads, so I cannot add overload of get for compressed pair (fu=
nction template cannot be partially specialized). Furthermore, the standard=
solution to declare the get method in my class namsepace and use ADL will =
not work, because ADL is not invoked for function template class with expli=
citly provided argument (index).</span><br style=3D"font-family: Helvetica;=
font-size: 12px; font-style: normal; font-variant: normal; font-weight: no=
rmal; letter-spacing: normal; line-height: normal; orphans: auto; text-alig=
n: start; text-indent: 0px; text-transform: none; white-space: normal; wido=
ws: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=3D""></=
div></blockquote></div><br class=3D""><div class=3D"">ADL is invoked, as lo=
ng as a template declaration is visible.</div><div class=3D""><br class=3D"=
"></div><div class=3D""><font face=3D"Courier" class=3D"">namespace my_proj=
ect {</font></div><div class=3D""><font face=3D"Courier" class=3D""> =
template< typename ></font></div><div class=3D""><font face=3D=
"Courier" class=3D""> void get() =3D delete;</font></div><div =
class=3D""><font face=3D"Courier" class=3D""><br class=3D""></font></div><d=
iv class=3D""><font face=3D"Courier" class=3D""> std::tuple<=
; int > blah;</font></div><div class=3D""><font face=3D"Courier" class=
=3D""> int q =3D get< 0 >( blah );</font></div><div clas=
s=3D""><font face=3D"Courier" class=3D"">}</font></div><div class=3D""><br =
class=3D""></div><div class=3D""><a href=3D"http://coliru.stacked-crooked.c=
om/a/09441b3bf7b97111" class=3D"">http://coliru.stacked-crooked.com/a/09441=
b3bf7b97111</a></div><div class=3D""><br class=3D""></div><div class=3D"">T=
he problem is that it=E2=80=99s not idiomatic to call <font face=3D"Courier=
" class=3D"">get</font> without namespace qualification.</div><div class=3D=
""><br class=3D""></div><div class=3D"">I think this is just one aspect of =
the more general problem with ADL and idiomatically writing <font face=3D"C=
ourier" class=3D"">std::</font> which applies to many free functions. =
There has been discussion here with various solutions such as introducing <=
font face=3D"Courier" class=3D"">namespace adl</font>. It occurs to me that=
<font face=3D"Courier" class=3D"">std::swap</font>, <font face=3D"Courier"=
class=3D"">std::get</font>, <font face=3D"Courier" class=3D"">std::static_=
pointer_cast</font>, etc could be defined to use ADL. This solves the probl=
em at least up to having a common template signature =E2=80=94 there=E2=80=
=99s no way to call <font face=3D"Courier" class=3D"">std::get<index>=
(obj)</font> and still pass a non-type index argument of user-defined type.=
</div><div class=3D""><br class=3D""></div><div class=3D"">One possible imp=
lementation:</div><div class=3D""><br class=3D""></div><div class=3D""><div=
class=3D""><font face=3D"Courier" class=3D"">// Helper; could be folded in=
to members of tuple, pair, and array.</font></div><div class=3D""><font fac=
e=3D"Courier" class=3D"">template< typename ></font></div><div class=
=3D""><font face=3D"Courier" class=3D"">struct __is_tuple_like : false_type=
{};</font></div><div class=3D""><font face=3D"Courier" class=3D""><br clas=
s=3D""></font></div><div class=3D""><font face=3D"Courier" class=3D"">templ=
ate< typename ... t ></font></div><div class=3D""><font face=3D"Couri=
er" class=3D"">struct __is_tuple_like< tuple< t ... > > : true_=
type {};</font></div><div class=3D""><font face=3D"Courier" class=3D""><br =
class=3D""></font></div><div class=3D""><font face=3D"Courier" class=3D"">/=
/ Stop ADL from causing infinite template recursion.</font></div><div class=
=3D""><font face=3D"Courier" class=3D"">template< bool ></font></div>=
<div class=3D""><font face=3D"Courier" class=3D"">struct __get_lookup;</fon=
t></div><div class=3D""><font face=3D"Courier" class=3D""><br class=3D""></=
font></div><div class=3D""><font face=3D"Courier" class=3D"">template<&g=
t;</font></div><div class=3D""><font face=3D"Courier" class=3D"">struct __g=
et_lookup< false > {</font></div><div class=3D""><font face=3D"Courie=
r" class=3D""> template< size_t i, typename t ></font></=
div><div class=3D""><font face=3D"Courier" class=3D""> using r=
esult_type =3D decltype( get< i >( declval< t >() ) );</font></=
div><div class=3D""><font face=3D"Courier" class=3D"">};</font></div><div c=
lass=3D""><font face=3D"Courier" class=3D""><br class=3D""></font></div><di=
v class=3D""><font face=3D"Courier" class=3D"">// Overload enables std::get=
syntax to find user's ADL.</font></div><div class=3D""><font face=3D"Couri=
er" class=3D"">template< size_t i, typename t ></font></div><div clas=
s=3D""><font face=3D"Courier" class=3D"">typename __get_lookup< __is_tup=
le_like< decay_t< t > >::value >::template result_type< i=
, t ></font></div><div class=3D""><font face=3D"Courier" class=3D"">get(=
t && o )</font></div><div class=3D""><font face=3D"Courier" class=
=3D""> { return get< i >( forward< t >( o ) ); }</=
font></div><div class=3D""><br class=3D""></div></div><div class=3D""><a hr=
ef=3D"http://coliru.stacked-crooked.com/a/9700092ffab74633" class=3D"">http=
://coliru.stacked-crooked.com/a/9700092ffab74633</a></div><div class=3D""><=
br class=3D""></div><div class=3D"">Repeat this pattern for anything else w=
ith a generic-ish free function interface.</div><div class=3D""><br class=
=3D""></div></body></html>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--Apple-Mail=_8844A2F2-FFFA-47B8-8540-F39DEF04BB6C--
.