NULLでハマった

例えば、multimapで同じキーを持つ要素の個数を調べたいとしましょう。

#include <iostream>
#include <map>
#include <algorithm>
#include <functional>

using namespace std;

struct S { };

int main() {
    multimap<int,S *>   m;
    for(int n = 0; n < 3; n++) {
        m.insert(make_pair(1, new S()));
        m.insert(make_pair(2, new S()));
    }
    
    auto    r = m.equal_range(2);
    int     size = 0;
    for(auto p = r.first; p != r.second; ++p)
        size++;
    cout << size << endl;   // 3
    
    for(auto p = m.begin(); p != m.end(); ++p)
        delete p->second;
}

もちろんこのように辿っていけば数えることができますが、こんなことでループ回したくないですね。次のように再帰で関数も書けますが、これだけのために関数を作りたくありません。

template<typename T>
int count(T begin, T end) {
    return begin == end ? 0 : 1 + count(++begin, end);
}

そこでSTLアルゴリズムにそのものズバリはないかと探すと、なさそうです。ズバリじゃなくていいならfind_ifという関数があります。第3引数に叙述関数オブジェクトを指定しなければなりませんが、常にtrueを返す関数オブジェクトというのも用意されていないので、それも適当に作ります。

    auto    null = make_pair(0, NULL);
    const int   size = count_if(r.first, r.second,
                    bind2nd(not_equal_to<pair<int,S *>>(), null));

常に等しくないならなんでもいいだろう、と思ってコンパイルすると、

error C2440: '初期化中' : 'const int' から 'S *' に変換できません。

と怒られてしまいました。よく見たら、NULLがintと思われているんですね。この問題でつまづいたのは初めてかも。こうしたら一応通りました。

    auto    null = make_pair(0, (S *)NULL);

もちろん、C++0xならnullptrが使えて、

    auto    null = make_pair(0, nullptr);

もっとも、C++0xならラムダが使えて常にtrueを返すようにすればよいです。

    const int   size = count_if(r.first, r.second,
                    [] (pair<int,S *> p) { return true; });