bind と lambda と _1さん の相性問題
昨日のビルドできない問題ですが、結論としては boost::lambda::_1 と bind の _1 が被ってるとみなされることによる問題のようでした。つまり、VCのコンパイラ(プリコンパイル済みヘッダーを作る段階?)が悪いような気がします。それぞれの _1 は、違う名前空間に居るわけですから。
……とはいえ、個人的には boost 側がおかしいような気がしないでもないのです。いやまぁ、ライブラリ作られている方は、私よりよっぽど C++ に精通している事確実なので、何か深い理由があるのかもしれませんが…少なからず私には疑問が残る点がいくつかあったり。
ヘッダに書く "変数"
bind の _1 等 は、(VCの場合)次の様にヘッダに書かれています。
// placeholders.hpp(42) static boost::arg<1> _1; static boost::arg<2> _2; static boost::arg<3> _3; static boost::arg<4> _4; : :
まず、この点でおかしい気がするわけです。 なんで const修飾子が無いんだろう と。
const を付けた「定数(コンパイル時定数?)」であれば、ヘッダーに書いても多重定義とみなされずOKだったりします。
ところが、「変数」をヘッダー書いて、いろんな cpp から #include してしまうと、その変数のインスタンスが大量に出来てしまい「沢山定義されてます」コンパイルエラーが出てしまうハズなんですよ。
…いやまぁ、通常であれば実際はそんなエラー出ないので、C++の規格的に何か例外っぽいものがあるのかもしれませんが……。ウチ的には、なんで「定数じゃなくて変数なんだろう?」という疑問が一点。
名前空間
bind は boost 名前空間で定義されていますが、bind の _1 次のようにヘッダーに書かれています。
namespace { : static boost::arg<1> _1; static boost::arg<2> _2; static boost::arg<3> _3; static boost::arg<4> _4; : : } // unnamed namespace
…なんで boost名前空間に入れていないんだろう。
名前空間の最後に「unnamed namespace」なんてコメントが入っている以上、明らかに意思的に 無名名前空間 で定義している事がわかります。 …が、何でだろう…。
つか、ヘッダーで無名名前空間を利用するって何か利点あるんでしょうか…^^;
実質グローバルと扱いが変わらない気がするんですが……。
問題解決方法
結局 bind の _1等を boost 名前空間で定義されるように
namespace boost { : static boost::arg<1> _1; static boost::arg<2> _2; static boost::arg<3> _3; static boost::arg<4> _4; : : } // <del>unnamed</del> boost namespace
という感じにしたところ、ようやく何事も無かったかのようにビルドが通ってくれました。(なんで const が無くてもOKなのか良くわかりません^^;)
が、正直既存のライブラリにテコ入れして利用するって、なんか悔しいよね。(何
VC も変。
bind の _1 が lambda の _1被るとはいえ、定義されている場所は
_1; // bind の _1 は(実質)グローバル boost::lambda::_1; // lambda の _1 は lambda名前空間で定義されている
という具合に違ってるわけで、本当は何も被らないと思うワケですよ。 lambda の _1 を lambda::bind に投げるにしても、boost::lambda::_1 として修飾してあげないといけないですし。(…いやまぁ、なんかそれ以前に問題があるような気もしますけど)
VC側も、名前の解決法方法(プリコンパイル済みヘッダー作成時の何か?)がおかしいような気もします。
ただ、個人的には bind の _1 が boost 名前空間に入ってない方がおかしいような気がしてなりません。^^;
でも、私が利用し始めた boost 1.30 ぐらいからこんな仕様だった気もするので、やっぱり何か意思的な何かがあるんだろうなぁ…。う〜ん。なんなんだろう。
…あぁでも、それ以前に重大な問題があることに気づきました。
なんでマシンによってビルド結果が違ってくるんじゃろ?
やっぱり悪いのは VC 側かしら〜!?