Visual Studio 2008 RTM: 提出中のフィードバックはどうなった?
C# で出してた奴
以下のコードが True, False, False を返すというバグは修正され,直感通り True, False, True が返るようになりました.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Linq.Expressions; class Program { static void Main(string[] args) { Expression<Func<bool, Func<bool>>> expr = cond => () => cond; var identity = expr.Compile(); var _true = identity(true); Console.WriteLine(_true()); var _false = identity(false); Console.WriteLine(_false()); Console.WriteLine(_true()); } }
STL/CLR で出してた奴
Feedback ID 303593,直ってなかった……
// Verifiable IL Code: /clr:safe #include <cliext/vector> using namespace System; public value class MyClass { public: int m_number; void Inc() { ++m_number; } virtual System::String^ ToString() override { return m_number.ToString(); } static bool operator == (MyClass a, MyClass b) { return a.m_number == b.m_number; } }; int main(array<System::String ^> ^args) { cliext::vector<MyClass> myvec; myvec.push_back( MyClass() ); myvec[0].Inc(); Console::WriteLine(myvec[0]); myvec[0].Inc(); Console::WriteLine(myvec[0]); myvec[0].Inc(); Console::WriteLine(myvec[0]); myvec.at(0).Inc(); Console::WriteLine(myvec[0]); myvec.at(0).Inc(); Console::WriteLine(myvec[0]); myvec.at(0).Inc(); Console::WriteLine(myvec[0]); return 0; }
結果.
0 0 0 1 2 3
[ ] でコピーが返る一方で at では参照が返るため,インデックスの境界チェックを行うという違いどころじゃなく動作が別物になってると.「STL/CLR の collection_adapter は要注意」の件と言い,STL/CLR はまだちょっと人に勧めるという代物じゃないような気がします.
追記
この STL/CLR の挙動ですが,IVector<T> のインデクサを C# / Visual Basic から使えるようにするために,敢えてこうしているというのは十分に考えられます.(つまり,バグではなく by-design)
επιστημη氏のところのコメントにも書きましたが,C++ でのいわゆる「参照を返す関数」を値型について実装しようとすると,C# の ref に相当するものを戻り値で行う必要があります.「参照を返す」,つまり byref return は,古い CLI 規格 (.NET 1.1 相当) では検証エラーになる動作でしたが,C++ サポートのためには必要だろうということで,新しい CLI 規格 (.NET 2.0 相当) に追加された仕様です.
しかし,byref return は C# や Visual Basic ではサポートされません (CLS にも入ってなかったかも).[ ] 演算子の動作を,C# や Visual Basic のインデクサと敢えてあわせたとすれば,[ ] と at の違いが by-design であってもまあ不思議ではないと.
ただやはり,こういった落とし穴が多いと,普通の C++ 使いに STL/CLR は奨めにくいというのが率直な感想です.