我正在维护一个std::tuple
迭代器来实现类似压缩迭代器的东西。
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... ) ;
}
现在我想实现迭代器操作,例如operator++
。基本思想是ZipIterator::++
只是++
元组中托管的所有迭代器。到目前为止我所拥有的是:
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... ) ;
}
我想提请注意这一部分:
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) ;
}
所以我现在所做的就是从increment
返回一些内容,然后将其发送到nothing
函数中,该函数不执行任何操作。还有另一种方式,例如我试过了:
template <int... S>
void increment_all(sequence<S...>) {
{ increment<S>()... ; } ;
}
但我明白了:
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>() ... ; } ;
^
我也有:
template <int... S>
void increment_all(sequence<S...>) {
std::make_tuple( increment<S>() ... ) ;
}
但这似乎是浪费,因为我根本不打算使用元组。事实上,我想要一个可以increment
返回void
的解决方案。
编辑:
基于各种评论,我现在有了这个,在预处理器的帮助下。
#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 :(得分:2)
我会在此示例中使用enable_if
实现它:
#include <vector>
#include <tuple>
#include <type_traits>
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 ;
ZipIterator( const Args&... args ) :
tuple( args.begin() ... ){} ;
ZipIterator& operator++(){
increment_all<0>();
return *this ;
}
private:
template <unsigned Index>
inline typename std::enable_if<(Index<sizeof...(Args)), void>::type increment_all(){
++std::get<Index>(tuple);
increment_all<Index+1>();
}
template <unsigned Index>
inline typename std::enable_if<(sizeof...(Args)<=Index), void>::type increment_all()
{}
IteratorTuple tuple ;
};
template <typename... Args>
ZipIterator<Args...> zip( Args&&... args ){
return ZipIterator<Args...>( args... ) ;
}
int main() {
std::vector<int> v1 {{1, 2, 3, 4}};
std::vector<double> v2 {{1, 2, 3, 4}};
auto zipped = zip(v1,v2);
++zipped;
return 0;
}
dummy
技巧有效,但看起来不合适。