copy_n

copy_n()という関数は標準にはない*1。fill_nはあるのに。なんでないのか?その理由は良くわかってない。
copy_nの存在価値はあるか?あるとしたら最適化の考慮のためだろう。
copy_nは条件次第で最適化により高速な関数memmoveまたはmemcpyに置き換える。
このときこれらの関数の引数は

void *memcpy( void *to, const void *from, size_t count );

といったようにコピーする数を指定するのでcopyよりcopy_nによりマッチする。
copy_nの引数であるイテレータが以下の条件をクリアする必要がある。

一番目の条件に対しては

boost::is_pod< typename iterator_traits<IT>::value_type >::value//trueならOK

で検出できる。is_podは現行のコンパイラでは正確には動作しない。なぜってPODには単純な構造体・共有型などの複合型も含まれるからだ。まあ組み込み型*2だったらOKってことでもいいんじゃないかと思う。

2番目の条件がむずかしい。
これはつまりイテレータの指している先がメモリ上で連続でなくてはいけない。IT型の任意のイテレータiterにおいて以下のことを保障しなくてはならない。

&(*(iter++)) == (&(*iter))++

このイテレータの性質を静的に判断することは、そのイテレータがポインタであること以外にはできない。かといって上記の検査を全てのイテレーションで行うのは意味がない。
では標準ではどうしているか?手元のMinGWgccの該当部分を見てみると条件を満たすイテレータは__Normal_iteratorなるものから継承される。その上でアルゴリズムcopyなどはこれを検出し特別化している。しかし__Normal_iteratorは標準ではない。
実際、標準のcopyはイテレータがメモリ連続であることを保障した(__Normal_iteratorを継承した)標準コンテナのイテレータポインタ以外は最適化できない。

最後にmemcpy、memmoveどちらにすべきかという問いに対しては入力イテレータと出力イテレータのさす範囲が重なっていたらmemmoveそうでなかったらmemcpyということができる。でもこれは実行時にしか判断できない。つまりif分による分岐が必要なわけだが、memmoveとmemcpyの速度差を考えるとコストがでかすぎる。よほどでかい配列のコピーでもなければ。

fillとfill_nのことも考える。これらの関数が最適化により高速な関数に置き換わるとすれば

void *memset( void *buffer, int ch, size_t count );

だろう。この関数は初期値指定にint型の値を指定する。しかしコピー数を指定するcountが1バイトの大きさを基準にしている。
このため標準ではイテレータがchar*またはunsigned char*であるときにのみ最適化をしている。そのほかの組み込み型のポインタでは最適化はできない*3

さてfillを使いたいとき、かなりの割合で配列を0で初期化したい場合(O埋め)なんじゃないかなと思う。
で上記の理由からchar型以外の配列には最適化が効かない。しかし整数型のすべては0は0(すべてのビットが0)である。また浮動小数点型においてもそれがIEEE754規格にそっている限り0は0である。
このことから0埋め用の関数を作っておくと便利かもしれない。memsetが使える条件は

である。1番目2番目の条件からイテレータは組み込み型のポインタでなければならない。3番目の条件はnumeric_limitsのstaticメンバis_iec559を調べればよい。

template<class T>
struct is_void<T>{static const bool value = false;}
template<>
struct is_void<void>{static const bool value = true;}

template<class T>
struct is_pointer<T>{static const bool value = false;}
template<class T>
struct is_pointer<T*>{static const bool value = true;}
	
template<class IT,bool B = true>
struct fill_zero_n_imp{
	inline static void func(IT first,size_t n){
		typedef typename std::iterator_traits<IT>::value_type value_type;
		std::memset(reinterpret_cast<void*>(first),0,n*sizeof(value_type));
	}
};
	
template<class IT>
struct fill_zero_n_imp<IT,false>{
	inline static void func(IT first,size_t n){
		typedef typename std::iterator_traits<IT>::value_type value_type;
		value_type temp = value_type();
		while(n--){
			*first = temp;
			++first;
		}
	}
};
	

	
template<class IT,class Sz>
inline void fill_zero_n(IT first,Sz n){
	typedef typename std::iterator_traits<IT>::value_type value_type;
	typedef std::numeric_limits<value_type> NL;
	
	static const bool is_optimize = 
	(is_pointer<IT>)
	&
	((NL::is_integer)|(NL::is_iec559)|(is_void<value_type>::value)|(is_pointer<value_type>::value));
		
	fill_zero_n_imp<value_type,is_optimize>::func(first,n);
}

まあそこまで最適化にこだわるのはアレだと思うが、案外最適化されないことって多いんだと思う。

*1:SGI版には存在

*2:整数型、浮動小数点型、ポインタ、void

*3:sizeof(T)<=sizeof(int)の型ならできそうな気もするけど