template引数にコンテナを指定し、関数内でiterateする方法
自分が修士の学生でC++を書いていたとき、どうにも分からなかったことがある。それは、template関数のtemplate引数にstd::vectorなどのコンテナを指定し、関数内でそのコンテナに対してiteratorを回す方法である。当時の自分は以下のようなコードを書いており、コンパイルエラーから抜けだせなくなった。
template <class X> void iterateTest(const X& var) { // Xはstd::vectorなどのコンテナであり、以下でそのconst_iteratorにアクセスしたい for(X::const_iterator itr = std::begin(var); itr != std::end(var); itr++) { std::cout << *itr << std::endl; } }
これがコンパイルエラーになる理由が当時全く分からず、最終的に諦めてしまったのであった。
しかし、最近これに対する解答を見つけた。それが以下のコードである。
template <class X> void iterateTest(const X& var) { // X::const_iteratorの前にtypenameを付け、これが型名であることを明示 for(typename X::const_iterator itr = std::begin(var); itr != std::end(var); itr++) { std::cout << *itr << std::endl; } }
つまり、型名の前にtypenameをつければよかったのである。こうしなければならない理由は、X::const_iteratorとだけ書くと、これがXクラスのconst_iteratorという名前のstatic変数とも解釈できるなど、Xの正体がこの時点で不明であるがために、解釈が一意に定まらないためである。
さて、これでようやく長年の疑問が解決したわけだが、実はもっと簡単に書ける方法があることを発見した。それはrange based forを使う方法である。コードを以下に示す。
template <class X> void iterateTestNew(const X& var) { // range based forを使えばよりスッキリ書ける for(const auto& el : var) { std::cout << el << std::endl; } }
以前の記事でも取り上げたrange based forにまさかこんな使い道があったとは・・・C++はまだまだ知らないことが多く、いろんな場面で損をしていると思う。今後も着実に勉強を進め、効率のよいコードを書けるようになりたい。