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&lt;T&gt; <br>=C2=
=A0 - trait std::tuple_element&lt;I, T&gt; <br>=C2=A0 - function template s=
td::get&lt;I&gt;(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&lt;I&gt;(t) definition should be changed to=
 invoke tuple_get(std::integral_constant&lt;std::size_t, I&gt;{}, 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&lt;std::si=
ze_t I, typename T&gt;<br>enable_if_t&lt;I =3D=3D 0, tuple_element_t&lt;I, =
decay_t&lt;I&gt;&gt;&gt; const&amp; get(T const&amp; t);<br><br>template&lt=
;std::size_t I, typename T&gt;<br>enable_if_t&lt;I !=3D 0, tuple_element_t&=
lt;I, decay_t&lt;I&gt;&gt;&gt; const&amp; get(T const&amp; 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&lt;0, decay_t&lt;I&gt;&gt; cons=
t&amp; tuple_get(integral_constant&lt;std::size_t, 0&gt;, T const&amp;);</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&lt;std::size_t I, typename T&gt;</span><br><=
span style=3D"font-family: courier new,monospace;">tuple_element_t&lt;I, de=
cay_t&lt;I&gt;&gt; const&amp; tuple_get(integral_constant&lt;std::size_t, I=
&gt;, T const&amp;)</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&lt;typename T, typename Tuple, typename =3D enable_if_t&l=
t;only_one&lt;T, std::decay_t&lt;Tuple&gt;&gt;::value&gt;&gt;<br>T const&am=
p; get(Tuple const&amp;) { return tuple_get(index_of&lt;T, std::decay_t&lt;=
Tuple&gt;&gt;{}, t); }<br></span>only_one&lt;T, std::decay_tuple_t&lt;tuple=
&gt;&gt;::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&lt;std::size_t, I&gt;). 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&quot; 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 &lt;<a href=3D"mailto:tomaszkam@gmail.com" =
class=3D"">tomaszkam@gmail.com</a>&gt; 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"">&nbsp; =
&nbsp; template&lt; typename &gt;</font></div><div class=3D""><font face=3D=
"Courier" class=3D"">&nbsp; &nbsp; 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"">&nbsp; &nbsp; std::tuple&lt=
; int &gt; blah;</font></div><div class=3D""><font face=3D"Courier" class=
=3D"">&nbsp; &nbsp; int q =3D get&lt; 0 &gt;( 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>&nbsp;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&lt;index&gt;=
(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&lt; typename &gt;</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&lt; typename ... t &gt;</font></div><div class=3D""><font face=3D"Couri=
er" class=3D"">struct __is_tuple_like&lt; tuple&lt; t ... &gt; &gt; : 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&lt; bool &gt;</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&lt;&g=
t;</font></div><div class=3D""><font face=3D"Courier" class=3D"">struct __g=
et_lookup&lt; false &gt; {</font></div><div class=3D""><font face=3D"Courie=
r" class=3D"">&nbsp; &nbsp; template&lt; size_t i, typename t &gt;</font></=
div><div class=3D""><font face=3D"Courier" class=3D"">&nbsp; &nbsp; using r=
esult_type =3D decltype( get&lt; i &gt;( declval&lt; t &gt;() ) );</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&lt; size_t i, typename t &gt;</font></div><div clas=
s=3D""><font face=3D"Courier" class=3D"">typename __get_lookup&lt; __is_tup=
le_like&lt; decay_t&lt; t &gt; &gt;::value &gt;::template result_type&lt; i=
, t &gt;</font></div><div class=3D""><font face=3D"Courier" class=3D"">get(=
 t &amp;&amp; o )</font></div><div class=3D""><font face=3D"Courier" class=
=3D"">&nbsp; &nbsp; { return get&lt; i &gt;( forward&lt; t &gt;( 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&quot; 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--

.