状況説明
std::accumulate
を使ってコンテナ内の数値の平均を求める関数を書いた。
(正確に言えばfirst
からend
までの平均)
template<typename InputIt>
double mean(InputIt first, InputIt last,size_t size){
return std::accumulate(first,last,0.0) / size;
}
平均なのだからdouble
で帰ってくれば良いという考え。
本題
int
のコンテナからもdouble
の結果を返すようなことになるのは腑に落ちない。
引数のイテレータから型を取り出すように変更。
ついでに要素数もイテレータの距離で計算するようにした。
2015/06/09 追記:イテレータ間の距離を(last-first)
で求めるには、ランダムアクセスイテレータが必要らしい。std:distance(first,last)
なら他のイテレータでも問題ないそうなのでそっちに変更。
template<typename It>
using v_type = typename std::iterator_traits<It>::value_type;
template<typename InputIt>
v_type<InputIt> mean(InputIt first, InputIt last){
return std::accumulate(first,last,v_type<InputIt>(0)) / std::distance(first,last);
//return std::accumulate(first,last,v_type<InputIt>(0)) / (last-first);
}
型名がiterator_traits
のせいで長いので、エイリアステンプレートで別名をつけた。
疑問
上のやつの方が「イテレータ使ってる感」は強いが、このシチュエーションなら次のコードでよいのではないだろうか? 気持ち以上の差はあるのだろうか?
2015/06/09 追記:答えを教えていただいた。この書き方だとメモリ領域が不連続なコンテナ(std::list
など)には使えないそうだ。
std::vector
などに使う分にはこれでよいようだが。
2015/06/09 追記 : なにか考え違いをしていたようだ。この形はC配列かstd::array
とかが対象でないと手元の環境(clang 3.6.1)ではコンパイルが通らない。イテレータは一般にポインタに変換することはできないようだ。
template<typename T>
T mean(T* first, T* last){
return std::accumulate(first,last,T(0)) / (last-first);
}
iterator_traits
今回のシチュエーションでは使わないが、iterator_traits
はイテレータが示すものの型(value_type
)以外の情報も含んでいる。
たとえば引き算の結果の型(difference_type
)とか、イテレータ自身の種類(iterator_category
)とか。