読者です 読者をやめる 読者になる 読者になる

iteratorを引数にするジェネリック関数 iterator_traits

C++

例えば2つのイテレータを受け取って平均を返す関数を書こうとすると、イテレータが指し示す型の情報がないと作れませんね。
こんなときは iterator_traits というものを使って書くようです。
例えば平均値を求める関数を書いてみると、次のようになります。
戻り値の型を typename std::iterator_traits::value_type としています。
また合計値を求めるのはaccumulate()関数で行ってますが、この引数として value_type(0)が必要です。この value_type は関数冒頭でtypedefしています。
これは組み込み型の配列にも使えます。便利ですね。

#include <iostream>
#include <algorithm>
#include <numeric>
#include <stdexcept>
#include <iterator>

#include <vector>

template<class In>
typename std::iterator_traits<In>::value_type my_ave(In b, In e)
{
    typedef std::iterator_traits<In>::value_type    value_type;
    
    value_type sum = std::accumulate(b, e, value_type(0));

    if (b != e) {
        return sum / (e - b);
    } else {
        throw std::invalid_argument("no data");
    }
}

int main()
{
    // vectorの要素(double)の平均値
    std::vector<double> v;
    for (int i = 0; i < 10; i++ ) {
        v.push_back(i);
    }
    std::cout << my_ave(v.begin(), v.end()) << std::endl;
    // クリアすると、例外が発生
    v.clear();
    try {
        std::cout << my_ave(v.begin(), v.end()) << std::endl;
    }
    catch(std::logic_error e) {
        std::cout << e.what() << std::endl;
    }
    // doubleの配列にも使える
    const double    va[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    std::cout << my_ave(va, va + sizeof(va)/sizeof(*va)) << std::endl;
    
    return 0;
}