I'm maintaining a std::tuple
of iterators to implement something like a zipped iterator.
template <typename... Args>
class ZipIterator {
public:
typedef typename std::tuple< typename std::decay<Args>::type::iterator ... > IteratorTuple ;
ZipIterator( const Args&... args ) :
tuple( args.begin() ... ){} ;
private:
IteratorTuple tuple ;
} ;
template <typename... Args>
ZipIterator<Args...> zip( Args&&... args ){
return ZipIterator<Args...>( args... ) ;
}
Now I'd like to implement iterator operations like e.g. operator++
. The basic idea being that ZipIterator::++
just ++
all of the iterators hosted in the tuple. What I have so far is this:
template<int ...>
struct sequence {};
template<int N, int ...S>
struct gens : gens<N-1, N-1, S...> {};
template<int ...S>
struct gens<0, S...>{
typedef sequence<S...> type;
};
template<typename... Args>
struct index_sequence {
typedef typename gens<sizeof...(Args)>::type type ;
} ;
template <typename... Args>
class ZipIterator {
public:
typedef typename std::tuple< typename std::decay<Args>::type::iterator ... > IteratorTuple ;
typedef typename std::tuple< typename std::decay<Args>::type::iterator::value_type ... > ValueTuple ;
typedef typename index_sequence<Args...>::type Sequence ;
ZipIterator( const Args&... args ) :
tuple( args.begin() ... ){} ;
ZipIterator& operator++(){
increment_all( Sequence() ) ;
return *this ;
}
ValueTuple operator*(){
return deref( Sequence() ) ;
}
private:
template <typename... Pack>
void nothing( Pack... ){}
template <int... S>
void increment_all(sequence<S...>) {
nothing( increment<S>()... ) ;
}
template <int S>
typename std::tuple_element<S,IteratorTuple>::type increment(){
return ++std::get<S>(tuple) ;
}
template <int... S>
ValueTuple deref( sequence<S...> ){
return ValueTuple( *std::get<S>(tuple) ... ) ;
}
IteratorTuple tuple ;
} ;
template <typename... Args>
ZipIterator<Args...> zip( Args&&... args ){
return ZipIterator<Args...>( args... ) ;
}
I'd like to draw attention to this part:
template <typename... Pack>
void nothing( Pack... ){}
template <int... S>
void increment_all(sequence<S...>) {
nothing( increment<S>()... ) ;
}
template <int S>
typename std::tuple_element<S,IteratorTuple>::type increment(){
return ++std::get<S>(tuple) ;
}
So what I do now is return something from increment
and then send this into the nothing
function that does ... nothing. Is there another way, e.g. I've tried:
template <int... S>
void increment_all(sequence<S...>) {
{ increment<S>()... ; } ;
}
But I get:
file5e1e684094e9.cpp:51:29: error: expected ';' after expression
{ increment<S>() ... ; } ;
^
;
file5e1e684094e9.cpp:51:15: error: expression contains unexpanded parameter pack 'S'
{ increment<S>() ... ; } ;
^ ~
file5e1e684094e9.cpp:51:30: error: expected expression
{ increment<S>() ... ; } ;
^
I also have:
template <int... S>
void increment_all(sequence<S...>) {
std::make_tuple( increment<S>() ... ) ;
}
But it seems like a waste as I'm not going to use the tuple at all. In fact, I'd like a solution where I can have increment
return void
.
edit:
Based on the various comments, I now have this, with some help from the preprocessor.
#define DO_PREFIX(PREFIX) nothing( ( PREFIX std::get<S>(tuple) , 0 )... )
#define DO_SUFFIX(SUFFIX) nothing( ( std::get<S>(tuple) SUFFIX , 0 )... )
template <int... S>
void increment_all(sequence<S...>) {
DO_PREFIX(++) ;
}
template <int... S>
void decrement_all(sequence<S...>) {
DO_PREFIX(--) ;
}
template <int... S>
void increment_all(int n, sequence<S...>) {
DO_SUFFIX(+=n) ;
}
template <int... S>
void decrement_all(int n, sequence<S...>) {
DO_SUFFIX(-=n) ;
}
(), 0)... };` or something like that.– Kerrek SB Jun 05 '14 at 08:29(), 0)...)` should do the trick.– Jarod42 Jun 05 '14 at 09:25(tuple) ) ;`. Too bad we can't pack expand statements ...– Romain Francois Jun 05 '14 at 09:55