Topic: peeling off" a tuple
Author: Andy Venikov <swojchelowek@gmail.com>
Date: Thu, 13 May 2010 12:06:37 CST Raw View
I'm looking at the API for the tuple in the FCD, and there doesn't seem to
be a way to "peel" the tuple off.
For example, I want to be able to get the first tuple element and treat
the rest of the tuple recursively.
void f(tuple<> & emptyTuple)
{
//End of recursion
}
template <typename Head, typename ... Tail>
void f(tuple<Head, Tail...> & inTuple)
{
DoSomethingWithElement(get<0>(inTuple));
f(inTuple.GetTail()); //Won't compile: GetTail
//Doesn't exist
};
This seems very reasonable and something I used to do with home-grown
tuples. Since there is no other sensible way to implement tuple other than
recursive inheritance, GetTail could be a simple cast of this to the parent.
Or am I mistaken and there is a way to that?
Thanks,
Andy.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: David Krauss <potswa@gmail.com>
Date: Fri, 14 May 2010 15:48:04 CST Raw View
On May 13, 1:06 pm, Andy Venikov <swojchelo...@gmail.com> wrote:
> I'm looking at the API for the tuple in the FCD, and there doesn't seem to
> be a way to "peel" the tuple off.
> For example, I want to be able to get the first tuple element and treat
> the rest of the tuple recursively.
>
> void f(tuple<> & emptyTuple)
> {
> //End of recursion
>
> }
>
> template <typename Head, typename ... Tail>
> void f(tuple<Head, Tail...> & inTuple)
> {
> DoSomethingWithElement(get<0>(inTuple));
> f(inTuple.GetTail()); //Won't compile: GetTail
> //Doesn't exist
>
> };
>
> This seems very reasonable and something I used to do with home-grown
> tuples. Since there is no other sensible way to implement tuple other than
> recursive inheritance, GetTail could be a simple cast of this to the parent.
That would be unnecessarily restrictive of the implementation.
> Or am I mistaken and there is a way to that?
Huh, I tried Googling it and there still doesn't seem to be a good
reference.
Try iterating with a size_t and terminating with SFINAE.
template< size_t tuple_index, class... T >
typename std::enable_if< tuple_index == sizeof...(T) >::type
f( std::tuple< T... > const & ) {}
template< size_t tuple_index = 0, class... T >
typename std::enable_if< tuple_index < sizeof...(T) >::type
f( std::tuple< T... > const &in ) {
do_something( std::get<tuple_index>( in ) );
f< tuple_index+1, T... >( in );
}
f( my_tuple );
This works in GCC; I'm not sure if that usage of default function
template arguments is entirely correct.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Andy Venikov <swojchelowek@gmail.com>
Date: Sat, 15 May 2010 20:16:00 CST Raw View
David Krauss wrote:
>
> On May 13, 1:06 pm, Andy Venikov <swojchelo...@gmail.com> wrote:
<snip>
>>
>> This seems very reasonable and something I used to do with home-grown
>> tuples. Since there is no other sensible way to implement tuple other than
>> recursive inheritance, GetTail could be a simple cast of this to the parent.
>
> That would be unnecessarily restrictive of the implementation.
Maybe. But what are the options? Are you going to specialize tuple<>
for every arity?
like
templte <typename ... T> struct tuple;
template <typename T1> struct tuple<T1> {T1 var1; ...};
template <typename T1, typename T2> struct tuple<T1, T2>
{
T1 var1;
T2 var2;
...
};
.........
Seems kinda tedious. It's a lot easier to just:
template <typename Head, typename ... T> struct tuple
: public tuple<T...>
{
Head my_arg;
};
template <> struct tuple<> {};
And that's it.
>
>> Or am I mistaken and there is a way to that?
>
> Huh, I tried Googling it and there still doesn't seem to be a good
> reference.
>
> Try iterating with a size_t and terminating with SFINAE.
>
<snip>
Yes, that's what I'm forced to do right now. But that forces you to
create a lot of specializations. Not only do I have to have a
specialization (actually an overload) when Index == sizeof ...(T)
I also need to have an overload for an empty tuple. (because my
function can be called with a tuple of any size, including 0)
With the other approach you just have an overload with an empty tuple
and you're golden.
Andy.
P.S. Well, after writing my reply I just realized that I don't need an
overload for an empty tuple. The overload enabled for Index == sizeof
...(<empty>) will be picked up. My solution looked a lot uglier than
yours because I didn't use a default value for Index - thanks for the
idea.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: David Krauss <potswa@gmail.com>
Date: Sun, 16 May 2010 22:22:09 CST Raw View
Re the last thing I said, here's a version that works with GCC 4.5:
template< class T, class F,
size_t tuple_index0 = std::tuple_size<T>::value,
size_t... tuple_indexes >
typename std::conditional< tuple_index0,
typename std::enable_if< tuple_index0 == 0 >::type,
typename std::result_of< F( typename
std::tuple_element<tuple_indexes-1, T>::type... ) >::type
>::type
apply( T const &t, F const &f ) {
return f( std::get< tuple_indexes - 1 >( t )... );
}
template< class T, class F,
size_t tuple_index0 = std::tuple_size<T>::value,
size_t... tuple_indexes >
typename std::conditional< tuple_index0,
decltype( apply< T, F, tuple_index0 - 1, tuple_index0,
tuple_indexes... >
( std::declval<T>(), std::declval<F>() ) ),
typename std::enable_if< tuple_index0 >::type
>::type
apply( T const &t, F const &f ) {
return apply< T, F, tuple_index0 - 1, tuple_index0,
tuple_indexes... >( t, f );
}
Without the last enable_if, GCC goes into an infinite spin.
As an observation, it seems hard to keep the index to
std::tuple_element in bounds. It would be nice if the behavior
included bounds checking, and no "type" member on out-of-bounds.
Is there an idiom for terminating or short-circuiting evaluation
within an SFINAE expression?
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: David Krauss <potswa@gmail.com>
Date: Sun, 16 May 2010 22:22:18 CST Raw View
Sorry for the excessive posting... here is a "proper" function
template for applying a tuple/pair/array to a function. I really
shouldn't be doing this so late at night...
template< class T, class F,
size_t tuple_index0 = std::tuple_size<T>::value,
size_t... tuple_indexes >
typename std::result_of<
typename std::enable_if< tuple_index0 == 0, F >::type //
workaround for GCC...
( typename std::tuple_element<tuple_indexes - 1,
typename std::enable_if< tuple_index0 == 0, T >::type >::type... )
>::type // ... as this enable_if results in a no-argument call rather
than SFINAE
apply( T const &t, F const &f ) {
return f( std::get< tuple_indexes - 1 >( t )... );
}
template< class T, class F,
size_t tuple_index0 = std::tuple_size<T>::value,
size_t... tuple_indexes >
decltype( apply< typename std::enable_if< tuple_index0 != 0, T
>::type,
F, tuple_index0 - 1, tuple_index0, tuple_indexes... >
( std::declval<T>(), std::declval<F>() ) )
apply( T const &t, F const &f ) {
return apply< T, F, tuple_index0 - 1, tuple_index0,
tuple_indexes... >
( t, f );
}
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: David Krauss <potswa@gmail.com>
Date: Sun, 16 May 2010 22:22:04 CST Raw View
On May 15, 9:16 pm, Andy Venikov <swojchelo...@gmail.com> wrote:
> Maybe. But what are the options? Are you going to specialize tuple<>
> for every arity?
Iterating up a chain of inheritance requires that the chain is in the
same order as the specification. Numerical indexes add a layer of
abstraction, so the implementation is free to sort the elements by
alignment.
> Yes, that's what I'm forced to do right now. But that forces you to
> create a lot of specializations. Not only do I have to have a
> specialization (actually an overload) when Index == sizeof ...(T)
> I also need to have an overload for an empty tuple. (because my
> function can be called with a tuple of any size, including 0)
> With the other approach you just have an overload with an empty tuple
> and you're golden.
I read up about tuples a bit more after writing my reply, and actually
there's an interface which is better than sizeof...(T):
std::tuple_size.
template< class T, size_t tuple_index = 0 >
typename std::enable_if< tuple_index == std::tuple_size<T>::value
>::type
f( T const & ) {}
template< class T, size_t tuple_index = 0 >
typename std::enable_if< tuple_index < std::tuple_size<T>::value
>::type
f( T const &in ) {
do_something( std::get<tuple_index>( in ) );
f< T, tuple_index+1 >( in );
}
This now works with std::array and std::pair.
I adapted it into a relatively succinct implementation of applying/
binding a tuple (pair, or array) to a function, but this doesn't
compile under GCC it seems to resolve overloading too late or
incorrectly and recursion never terminates. Any opinions on the
compliance of this code?
template< class T, class F,
size_t tuple_index0 = std::tuple_size<T>::value,
size_t... tuple_indexes >
typename std::enable_if< tuple_index0 == 0,
typename std::result_of< F( typename
std::tuple_element<tuple_indexes-1, T>::type... ) >::type
>::type
apply( T const &t, F const &f ) {
return f( std::get< tuple_indexes - 1 >( t )... );
}
template< class T, class F,
size_t tuple_index0 = std::tuple_size<T>::value,
size_t... tuple_indexes >
typename std::enable_if< ( tuple_index0 > 0 ),
decltype( apply< T, F, tuple_index0 - 1, tuple_index0,
tuple_indexes... >
( std::declval<T>(), std::declval<F>() ) )
>::type
apply( T const &t, F const &f ) {
return apply< T, F, tuple_index0 - 1, tuple_index0,
tuple_indexes... >( t, f );
}
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Larry Evans <cppljevans@gmail.com>
Date: Tue, 18 May 2010 14:03:31 CST Raw View
On May 15, 9:16 pm, Andy Venikov <swojchelo...@gmail.com> wrote:
[snip]
> > That would be unnecessarily restrictive of the implementation.
>
> Maybe. But what are the options? Are you going to specialize tuple<>
> for every arity?
>
> like
> templte <typename ... T> struct tuple;
> template <typename T1> struct tuple<T1> {T1 var1; ...};
> template <typename T1, typename T2> struct tuple<T1, T2>
> {
> T1 var1;
> T2 var2;
> ...
>
> };
>
> .........
>
> Seems kinda tedious.
[snip]
This is what boost::fusion::vector does. The tedium is
relieved by using boost::preprocessor. Maybe a similar
approach could be used here. The boost code is
browsable here:
https://svn.boost.org/trac/boost/wiki/BoostSubversion
HTH.
-Larry
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Andy Venikov <swojchelowek@gmail.com>
Date: Tue, 18 May 2010 14:00:49 CST Raw View
David Krauss wrote:
<snip>
> This now works with std::array and std::pair.
>
> I adapted it into a relatively succinct implementation of applying/
> binding a tuple (pair, or array) to a function, but this doesn't
> compile under GCC=85 it seems to resolve overloading too late or
> incorrectly and recursion never terminates. Any opinions on the
> compliance of this code?
>
> template< class T, class F,
> size_t tuple_index0 = std::tuple_size<T>::value,
> size_t... tuple_indexes >
> typename std::enable_if< tuple_index0 == 0,
> typename std::result_of< F( typename
> std::tuple_element<tuple_indexes-1, T>::type... ) >::type
>
>> ::type
>>
> apply( T const &t, F const &f ) {
> return f( std::get< tuple_indexes - 1 >( t )... );
> }
>
> template< class T, class F,
> size_t tuple_index0 = std::tuple_size<T>::value,
> size_t... tuple_indexes >
> typename std::enable_if< ( tuple_index0 > 0 ),
> decltype( apply< T, F, tuple_index0 - 1, tuple_index0,
> tuple_indexes... >
> ( std::declval<T>(), std::declval<F>() ) )
>
>> ::type
>>
> apply( T const &t, F const &f ) {
> return apply< T, F, tuple_index0 - 1, tuple_index0,
> tuple_indexes... >( t, f );
> }
>
I haven't read your other posts yet, so maybe you already covered it there,
but I think you don't need to have two overloads with enable_if. If you hav=
e
only one overload constrained by enable_if(index == size) and the other=
just
a plain overload, then for all cases when index != size, the more
specialized overload will be disabled hence the regular function will be
called, and when index == size, then the partial ordering rules will ki=
ck in
and the more specialized overload will be selected.
Andy.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Yechezkel Mett <ymett.on.usenet@gmail.com>
Date: Tue, 18 May 2010 14:04:03 CST Raw View
On May 17, 7:22 am, David Krauss <pot...@gmail.com> wrote:
> I adapted it into a relatively succinct implementation of applying/
> binding a tuple (pair, or array) to a function, but this doesn't
> compile under GCC=85 it seems to resolve overloading too late or
> incorrectly and recursion never terminates. Any opinions on the
> compliance of this code?
>
> template< class T, class F,
> size_t tuple_index0 = std::tuple_size<T>::value,
> size_t... tuple_indexes >
> typename std::enable_if< tuple_index0 == 0,
> typename std::result_of< F( typename
> std::tuple_element<tuple_indexes-1, T>::type... ) >::type>::type
>
> apply( T const &t, F const &f ) {
> return f( std::get< tuple_indexes - 1 >( t )... );
>
> }
>
> template< class T, class F,
> size_t tuple_index0 = std::tuple_size<T>::value,
> size_t... tuple_indexes >
> typename std::enable_if< ( tuple_index0 > 0 ),
> decltype( apply< T, F, tuple_index0 - 1, tuple_index0,
> tuple_indexes... >
> ( std::declval<T>(), std::declval<F>() ) )>::type
>
> apply( T const &t, F const &f ) {
> return apply< T, F, tuple_index0 - 1, tuple_index0,
> tuple_indexes... >( t, f );
>
> }
For SFINAE to work on the second specialization the enable_if<> first
has to be instantiated, which requires the decltype to be evaluated
(if that's the right term) which recurses. In other words, the
recursion is before the SFINAE.
Yechezkel Mett
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]