binder1stはとっても中途半端

引数を2つ取る関数の第一引数に実引数をbindして,引数を一つ取る関数に変換するためのクラス.ちなみに,第二引数にbindするのはbinder2nd.もひとつちなみに、binder1stがやってることをカリー化(curring)という.
binder1stはoperator()を提供するクラスであり,それをお手軽に作るためのヘルパー関数がbind1st().ここまではsgiのサイトを見ながらの復習.

さて,本当にやりたいのは3引数を取る関数に1つの値をbindして2引数の関数を作ること.具体的には,長い文字列docと,docの中の位置を指す2つのインデックスを取り,その位置からのsuffixを辞書順に比較したい.

bool suffix_lower(const string &str, size_t lh, size_t rh)
{
  for (;lh < str.size() && rh < str.size(); ++lh, ++rh) { 
    if (str[lh] < str[rh]) return true;
    if (str[lh] > str[rh]) return false;
  }
  if (lh > rh) return true; // 最後まで一致した場合は,短い方(=インデックスが終端に到達した方)が辞書順で先になる.
  return false; // lh == rh の時もfalse.
}

という関数を用意して,

  std::vector<size_t> sa;
  sa.reserve(doc.size()); // docは検索対象となるドキュメント.
  for (size_t i = 0; i < doc.size(); ++i) sa.push_back(i);

  std::sort(sa.begin(), sa.end(), std::bind1st(suffix_lower, doc));

とやりたかったのだが,残念ながらコレはエラーになる.std::bind1st()は3引数を取る関数には対応していないからだ.
・・・そういえば,std::binder1st()が中途半端すぎたから,boostがちゃんと汎用的なヤツを作ってたよな・・・と思い出して、boostのドキュメントを調べてみる.あった.(http://www.boost.org/libs/bind/bind.html)

ただ,プログラムを書いているPCにboostを入れて無くて,Windowsだからapt-getだけじゃ入らないので,あとでLinux上で書くときにboost使うことにして,とりあえずでっち上げのクラスでbindしておく.

struct suffix_lower_bind : public binary_function<size_t, size_t, bool> {
  suffix_lower_bind(const string &doc) : doc_(doc) {}
  bool operator()(size_t lh, size_t rh) const {
    return suffix_lower(doc_, lh, rh);
  }
private:
  const string &doc_;
};

C++0xでは,functional系の標準ライブラリはboostが要らないくらいマシになってたら良いな。

このブログに乗せているコードは引用を除き CC0 1.0 で提供します。