STL/CLRの謎(2)

STL/CLRの謎(1) - crimsonwoodsの日記の続きです。
IComparable^への変換と、pairの使い方そしてvectorの謎についてを見ていきます。

IComparable^への変換がなぜおきる?

この原因はcliext/utilityに

bool operator==(IComparable^ _Left, IComparable^ _Right);

が定義されていることと、pairに

template <typename _Pair_t> operator _Pair_t();

が定義されていることの2つの原因から起こります。


通常ハンドルの比較はObject::ReferenceEqualsと解釈されるはずなのですが、
pairに関しては"template operator _Pair_t()"が存在するため、
IComparable^への変換を通じて、"bool operator==(IComparable^ _Left, IComparable^ _Right)"が適用されるようです。


このような変換は通常のC++では明示的な型変換を指示しないかぎり起きないはずなのですが、
どういった理由かわ判りませんが、VC++2008EEのC++/CLIでは上記の用にコンパイラが解釈してしまう用です。

pairの想定されていた使い方?

cliext/utilityをさらに見ていくと、pairの比較演算子が定義されているのがわかります。

template <class _Ty1, class _Ty2> bool operator == (pair<_Ty1, _Ty2>% _Left, pair<_Ty1, _Ty2>% _Right );

これを見る限り、pairの比較についてはpair^というハンドルではなく、
pair%というpairインスタンスの追跡参照についてのみ適用されるということになります。
したがって、pairの比較が発生するような状況においてはpair^というハンドルの形ではなく、
pairインスタンスそのものである必要がありそうです。


ここから予想されることとして、vectorやlistなどのコンテナの要素として、
pairを使用する場合は、以下のようにハンドル型を要素とするのではなく、
pairそのものをtemplate parameterとして指定する必要があるだろうということです。

cliext::vector< cliext::pair< int, String^ >^ > pair_ref_values; // pairのハンドルを要素とする
cliext::vector< cliext::pair< int, String^ > > pair_values;      // pairそのものを要素とする

vector(実はlistなんかも)の謎

ここまでの流れでvectorにはpair^じゃなくてpairを渡せばいいのか!と思うわけですが、
実はそうもいかないのです。
実際にコードを書いてみるとわかるのですが、実はvectorは特殊化が行われており、
ref classの場合は必ずハンドル型をtemplate parameterとして取るようになっています。
このため、pairをvectorに渡したとしても、自動的にpair^として扱われるため、
やはりvector::IndexOfでコンパイルエラーとなります。


実はこの挙動はvectorに限らず、listなども同じようになっています。
STL/CLRの設計として何が正しく、実装として何が間違っているのかは作者にしかわかりません。


ただ、現状のSTL/CLRはあまり他人にお勧めできるような状態ではないのでしょう。
Service Packなどで改善されることを期待するしかないのかもしれません。