イテレータの受け取り方

以下のコードは、コンパイルエラーになる:

template <class Iterator>
Iterator f(const Iterator& it)
{
    return it;
}

int main()
{
    int ar[] = {1, 2, 3};
    f(ar); // コンパイルエラー!呼び出し可能なf()のオーバーロードがない
}

関数f()イテレータconst左辺値参照で受け取る。このようにした場合、テンプレートパラメータIteratorint[3]に推論される。C++の言語仕様として、組み込み配列はreturn文で返せないので、コンパイルエラーになる(実際には、戻り値型のところでSFINAEが起きる)。

以下のように、イテレータをコピーで受け取ることで関数f()を呼び出せるようになる:

template <class Iterator>
Iterator f(Iterator it)
{
    return it;
}

int main()
{
    int ar[] = {1, 2, 3};
    f(ar); // OK
}

こうすることで、テンプレートパラメータIteratorint*に推論される。ポインタはreturn文で返せるので、これは問題なく通る。

この変更が、C++14でのmake_move_iterator()関数の仕様に適用された。

ちなみに、この推論ルールは、decay(ディケイと読む)という名前で知られており、<type_traits>ライブラリにはその推論ルールを適用するメタ関数が定義されている。