BOOST_FOREACHの使い方

C++のコンテナ類を列挙するときに便利なのがboost::foreach。可変長配列であるvectorを列挙する場合は以下の感じ。

//---------------------------------------------------------------------------
#include <iostream>
#include <string>
#include <vector>
#include <boost/foreach.hpp>
#include <tchar.h>
//---------------------------------------------------------------------------
class CPlayer
{
public:
  CPlayer(const std::string& name, const std::string& position, int number) :
    Name(name), Position(position), Number(number)
  {
  }
  std::string Name;
  std::string Position;
  int Number;
};

int _tmain(int argc, _TCHAR* argv[])
{
  std::vector<CPlayer> Players;

  Players.push_back(CPlayer("Kazuyoshi MIURA", "FW", 11));
  Players.push_back(CPlayer("Shoji JO", "FW", 9));
  Players.push_back(CPlayer("Motohiro YAMAGUCHI", "MF", 6));
  // コンテナを列挙する
  BOOST_FOREACH(const CPlayer& Player, Players) {
    std::cout << Player.Name << ',' << Player.Position <<  ',' << Player.Number << std::endl;
  }
}

BOOST_FOREACHの第1引数にコンテナの要素型、第2引数にコンテナを渡すだけで列挙してくれるので、forループの為にイテレータを宣言したり*1、std::for_eachの為に関数オブジェクトを定義する*2必要が無い。

STL連想配列であるstd::mapをBOOST_FOREACHで列挙する場合、列挙型に値の型を指定しがち。この場合はエラーとなる。

typedef std::map<UnicodeString, TIniFile*> CConfigTable;
CConfigTable ConfigTable;
BOOST_FOREACH(TIniFile* pInifile, ConfigTable) { // ←コンパイルエラー
  TDateTime LastUpdate = pInifile->ReadTime("GLOBAL", "LastUpdate", TDateTime());
}

std::mapをBOOST_FOREACHで列挙する場合に使用する要素型は、std::mapで定義されているtypedef名*3のうち、value_typeが要素型となる。
これはstd::pair型なので、firstがキー、secondが値に対応する。

typedef std::map<UnicodeString, TIniFile*> CConfigTable;
CConfigTable ConfigTable;
BOOST_FOREACH(CConfigTable::value_type Elem, ConfigTable) {
  TDateTime LastUpdate = Elem.second->ReadTime("GLOBAL", "LastUpdate", TDateTime());
}

ちなみに、std::mapで定義している主なtypedef名は以下の通り。

説明
key_type キーの型
mapped_type 値の型
value_type キーと値の組み合わせ

上記の例だと、key_typeがUnicodeString、mapped_typeがTIniFile*となる。

*1:C++0xのautoならば多少マシだけど。

*2:これまた、C++0xラムダ式とかboost::lambdaならば多少マシ。でもBCC32.exeでboost::lambdaは…

*3:エイリアスと言ったほうがいいのかな…