C++にもPythonのenumerateがほしかった
Pythonにはenumerateというメソッドがあって、以下の様に使う。
In [1]: vec = [1,2,3,4,5] In [2]: for i,v in enumerate(vec): ...: print(i,v) 0 1 1 2 2 3 3 4
Pythonでいうところのforは、C++,Javaでいうところの拡張forにあたるもので、C++/Javaのようなfor(init;pred;change)のような、いわゆるforは存在しない。 拡張forを使いたいけれど、インデックスもほしい場合にenumerateは便利なのである。 それがC++にもほしかった。同じようなことを思っている人はたくさんいるようで、StackOverFlowにもいくつかあった。
c++ - Find position of element in C++11 range-based for loop? - Stack Overflow
ここのを見ながら自分流のC++で書いたのでメモ。
#include <iostream> #include <vector> using namespace std; #define debug(x) #x << "=" << x << "(L:" << __LINE__ << ")" template<typename T,typename IT> struct Indexer{ struct iterator{ typedef IT inner_iterator; typedef typename iterator_traits<inner_iterator>::reference inner_reference; struct reference : pair<size_t,inner_reference>{ reference(size_t s,inner_reference i) : pair<size_t,inner_reference>(s,i) {} const size_t& index = (*this).first; const inner_reference& value = (*this).second; }; iterator(inner_iterator i) : pos(0),it(i) {} reference operator*() const { return reference(pos,*it); } iterator& operator++(){ ++pos;++it; return *this; } iterator operator++(int){ iterator tmp(*this); ++(*this); return tmp; } bool operator==(const iterator& rhs) const{ return it == rhs.it; } bool operator!=(const iterator& rhs) const{ return !(*this == rhs); } private: size_t pos; inner_iterator it; }; Indexer(T& t): container(t) {}; iterator begin() const{ return iterator(container.begin()); } iterator end() const{ return iterator(container.end()); } private: T& container; }; template<typename T> Indexer<T,typename T::iterator> enumerate(T& t){ return Indexer<T,typename T::iterator>(t); } // value will be readonly. template<typename T> Indexer<T,typename T::const_iterator> const_enumerate(T& t){ return Indexer<T,typename T::const_iterator>(t); } // test codes. template<typename T> ostream& operator<<(ostream& os,const vector<T>& val){ os << "[ "; for(typename vector<T>::const_iterator it=val.begin(); it != val.end();++it){ os << *it << " "; } os << "]"; return os; } bool vector_ref_check(vector<int> v){ vector<size_t> e_index = {}; vector<int> e_value = {}; vector<int> org = v; for(auto p:enumerate(v)){ e_index.push_back(p.index); e_value.push_back(p.value); } bool ret = true; for(size_t i=0;i<v.size();i++){ ret = ret and (e_index[i] == i); ret = ret and (e_value[i] == v[i]); } cerr << "vector_change_check(" << org << ") -> " << ret << endl; cerr << " info" << endl; cerr << " end." << endl; return ret; } bool vector_change_check(vector<int> v){ vector<size_t> e_index = {}; vector<int> e_value = {}; vector<int> org = v; // remember! you can change p.second! It's reference. for(auto p:enumerate(v)){ p.first = 0; e_index.push_back(p.index); p.second = -1; e_value.push_back(p.value); } bool ret = true; for(size_t i=0;i<v.size();i++){ ret = ret and (e_index[i] == 0); ret = ret and (e_value[i] == -1); ret = ret and (v[i] == -1); } cerr << "vector_change_check(" << org << ") -> " << ret << endl; cerr << " info" << endl; cerr << " " << v << endl; cerr << " end." << endl; return ret; } bool vector_const_check(vector<int> v){ vector<int> org = v; for(const auto p:const_enumerate(v)){ // compile error. // p.second = -1; // p.first = -1; } bool ret = true; for(size_t i=0;i<v.size();i++){ ret = ret and v[i] == org[i]; } cerr << "vector_const_check(" << org << ") -> " << ret << endl; cerr << " info" << endl; cerr << " " << v << endl; cerr << " end." << endl; return ret; } int main(int argc,char **argv){ vector_ref_check({}); vector_ref_check({1}); vector_ref_check({1,2}) ; vector_ref_check({1,2,3}); vector_change_check({}); vector_change_check({1}); vector_change_check({1,2}); vector_const_check({1,2}); vector_const_check({1,2}); }