いろいろがんばりたいブログ

情報科学科の人がいろいろ書きます。

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});
}