STL/CLRの謎(1)
επιστημηさんのちょっと前のエントリのvectorにpairを食わせられない件。
ネタ元:もすぬごく不安な Visual Studio 2008
VC++2008EEを入れて試してみました。
ここであーだこーだ言ってもあまり意味はないのですが、
なんでこんなことになっているのかという純粋な興味からちょっと調べてみました。
試したコードは↓こんな感じ。
#include <cliext/vector> #include <cliext/utility> using namespace System; typedef cliext::pair< int, String^ > value_type; int main(array<System::String ^> ^args) { cliext::vector< value_type^ > vector_values; for ( int i = 0 ; i < 10 ; ++i ) { vector_values.push_back( gcnew value_type( i, i.ToString() ) ); } for each( value_type^ value in vector_values ) { Console::WriteLine( "vector = {0}", value->second ); } return 0; }
もちろんコンパイルエラーが出るわけです。
エラーの内容はこれ
error C2825: '_Pair_t': must be a class or namespace when followed by '::' C:\Program Files\Microsoft Visual Studio 9.0\VC\include\cliext/vector(1066) : see reference to function template instantiation 'cliext::pair<_Value1_t,_Value2_t>::operator _Pair_t(void)<System::IComparable^>' being compiled with [ _Value1_t=int, _Value2_t=System::String ^, _Pair_t=System::IComparable ^ ]
これを見ると、vector::IndexOfの中の要素の比較の際に、
pairのtemplate < typename _Pair_t > operator _Pair_t()が、
_Pair_t = IComparable^で呼び出されているわけです。
pairにoperator _Pair_t()なるものが存在することも謎なのですが、
それ以上になぜこれがIComparable^として呼び出されるのか不思議ですね。
通常は未定義のObject::ReferenceEqualsとして解釈されるはずがなぜか型変換が呼び出され、
さらにIComparable^に変換しようとしているわけです。
もちろんpairはIComparable^を継承していませんし、operator _Pair_t()はpairへの変換を前提として
記述されているため、コンパイルが通らないというわけです。
ではなぜ、IComparable^への変換が起きてしまうのでしょうか?
この謎については後で。さらにpairの想定されていた使い方とvectorの謎についても後で。