MSVCRT std::for each

提供:yonewiki

MSVC Runtimeリファレンスに戻る

概要

 for_each関数は引数の第1から引数の第2までのIterator(要素番号)による管理がされているobject全てに対して引数3の関数を実行する関数です。引数3の関数は通常ラムダ式を使って、第一引数の値から複数の実行コマンドと戻り値を記載します。引数1から引数2までのobjectは関数の引数として第3引数の関数の引数として受け取ることが出来ます。ラムダ式で記述する場合は[]()->(){}の手前の()内で引数を引数の第1~第2引数の型と対応が取れる必要があります。[]の中に書くキャプチャ(for_eachの外で使っていた変数を受け取る部分) ->() の()内で指定するのが、戻り値の型と変数名、{}内には、関数そのもの、要するにプログラムを記述します。


 例えば、以下のように定義して使います。

 std::for_each(
      Iterator型で要素番号を管理するクラスを使った関数適用の始まりの要素,
      Iterator型で要素番号を管理するクラスを使った関数適用の終わりの要素,
      各要素番号に対して実行する関数(ラムダ式)
   );

 例

 std::for_each(argvUTF16, argvUTF16 + argcUTF16,
      [&argvUTF8Q](const auto& arg) {
         argvUTF8Q.emplace_back(QString::fromUtf16(reinterpret_cast<const char16_t*>arg, -1).toUtf8());
      }
   );


 LPWSTR* argvUTF16がw_char型の先頭アドレスを保持していて、例えばargcUTF16要素数の2を足すとargvUTF16のアドレス格納bit数(32bit(=4byte) or 64bit(=8Byte)) に対して要素数2個分進んだところまで繰り返す感じです。例えば、argvUTF16に要素が1つだけならば、要素2はNULLになる感じで組み込まれるているので、for_eachの繰り返しは要素番号1の文字列、そして要素番号2のNULLの2つについて処理が行われ、NULLを受け取ったfor_eachはそこで処理を終えます。


 ということなので、for_eachで関数を繰り返し実行するようにプログラムはされていますが、要素数が2で、文字列が格納されている要素が実質1であれば、単純にQByteArrayテンプレート化されているvector型argvUTF8Qの最後尾に文字列を付け足す処理が実行されます。このとき、argvUTF8Qをあとで、使いたいのでfor_each内だけのオブジェクトでは活用できません。外からの引数としてラムダ式の [] 内に記述してある必要があります。[]はキャプチャと呼ばれます。そして、argにはLPWSTR* argvUTF16のアドレスが渡されconst char* argはキャストされてQString::fromUtf16静的メンバ関数を利用して、UTF-16にエンコードされます。さらにfromUtf16(xxx).toUtf8という記述であるため、UTF-16になった文字列が、UTF-8に変換された値がemplace_backの引数となるため、結局はargvUTF16から取り出された引数のargがUTF-8になってargvUTF8QというQByteArray型にテンプレート化されたvector型の値として、UTF-8形式の文字列を最後尾に持つようになります。


 サンプルプログラムのくせに、Qtというライブラリを使ったサンプルで、ややこしかったかな?Qtで提供されている型以外の型でも動きます。Qtっていうライブラリが便利だよっていうことと、いろいろな型で動かせるよということを言いたかっただけです。


 for_eachの動作が分かってもらえたかなと思っています。さらには文字列配列ポインタに整数を足すように記述をすると繰り返し処理したい要素数を指定したのと同じことになり、繰り返したい要素が指定できるということも理解できたと思います。現在、使われているプログラムが32bitアプリか64bitかに合わせてなので、配列要素数2個分まで繰り返すというものになっています。。このようなアドレスの型への整数の足し算の仕組みを理解していれば、理解はできると思います。Cpp ラムダ式はリンク先でも簡単に説明しています。サンプルプログラムを書くとか言っておきながらさぼってますけど。

 

MSVC Runtimeリファレンスに戻る