名前空間に関する事故

私の分野では,ns-2というシミュレータを使って性能評価をしたりします.今回は,そのns-2の(C++の)ソースコードに手を加えていたときの話.

mapを使いたくて,#include<map>と書いたのですが,インクルードしただけで突然次のようなコンパイルエラーが現れました.

/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/bits/stl_algobase.h: In function `const _Tp& std::max(const _Tp&, const _Tp&) [with _Tp = TracedInt]':
tcp/tcp-fs.cc:68:   instantiated from here
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/bits/stl_algobase.h:177: error: no match for 'operator<' in '__a < __b'

不思議に思い,エラーの元となったソースファイルを開いてみると,問題となっているのは,maxseq_ = max(maxseq_, highest_ack_);という記述のようです.これは,非常に嫌な予感がします.using namespace std;の記述もないのに,名前空間指定なしでコールされているmax()関数.さらに追ってみると,やはりといった感じで原因を突き止めることができました.原因はtemplate.hというヘッダファイルにある以下の定義でした.

inline int max(int a, int b)
{
    return a < b ? b : a;
}

STLのalgorithmで提供されているものと同名の関数がグローバル名前空間に定義されていたことで,mapと一緒にalgorithmがインクルードされた際におかしくなってしまったのだと思われます.これに加えて,明示的なキャストを怠ったことも災いしてコンパイルエラーが発生してしまったようです(highest_ack_は,TracedIntというns-2で独自に定義された型の変数で,template.hには,この型を引数とするmax()関数は定義されていない).

そういった訳で,今回の事例で得られた教訓.

  • C/C++標準ライブラリ位は,同名の関数が存在してないか一通り調べましょう.
  • 調べきれないのなら,名前空間を定義してその中で定義するようにしましょう.
  • キャストはサボらずに明示的に行いましょう.

ns-2もひどいな,と感じる部分が多々存在します.