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                      ]