WinRTはコレクションに対するイテレータが用意されているので、その点ではC++との親和性も良いです。
この例は、Twitterのトレンド(地域:東京)を取得してきて、ListBoxに格納するコードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #include <collection.h> #include <boost/range.hpp> #include <boost/range/algorithm.hpp> void Application1::MainPage::Button_Click(Platform::Object^ sender, RoutedEventArgs^ e) { using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; using namespace Windows::Data::Xml::Dom; auto loadOp = XmlDocument::LoadFromUriAsync(ref new Uri("https://api.twitter.com/1/trends/1118370.xml")); loadOp->Completed = ref new AsyncOperationCompletedHandler<XmlDocument^>([this](IAsyncOperation<XmlDocument^>^ op) { auto doc = op->GetResults(); IIterable<IXmlNode^>^ nodes = doc->SelectNodes("/matching_trends/trends/trend/text()"); boost::transform(nodes, back_inserter(this->TrendList->Items), [](IXmlNode^ trend) { return safe_cast<XmlText^>(trend)->Data; }); }); loadOp->Start(); } |
ラムダ式の中、IIterable<>からはInput Iteratorが取り出せます。これがtransformの入力側です。
一方、出力側のback_inserterはIVector<>に対するOutput Iteratorを返す関数で、もちろん末尾に要素を追加していきます。このアプリでは、XAML側で<ListBox Name=”TrendList” … />と宣言しており、this->TrendList->Items (ItemsControl.Itemsプロパティ)が返すItemCollectionクラスはIVector<Object^>などから派生しています。
……とまあ、こう書くためには、Boost.Rangeに対するゴニョゴニョとした準備が必要なんですけどね。Boost.Rangeの“Method 2: provide free-standing functions and specialize metafunctions”の方法を選んでいます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | namespace Windows { namespace Foundation { namespace Collections { template<typename T> auto range_begin(T^ r) -> decltype(begin(r)) {return begin(r);} template<typename T> auto range_end(T^ r) -> decltype(end(r)) {return end(r);} } } } namespace boost { template<typename T> struct range_mutable_iterator<::Windows::Foundation::Collections::IIterable<T>^> { typedef ::Platform::InputIterator<T> type; }; template<typename T> struct range_const_iterator<::Windows::Foundation::Collections::IIterable<T>^> { typedef ::Platform::InputIterator<T> type; }; } |
このように、IIterable<>からイテレータを取り出す関数はbegin/endという名前(しかもIIterable<>と同じ名前空間で定義)なので、Range-based forと相性ばつぐん、のはずですが、このVisual C++にはまだRange-based forが実装されていないというオチが待っています(VC++独自のfor eachはだめでした。Range-based forのルールに対応していないようです)。
なお、今回使ったWinRTのイテレータ周りの対応は、Metro style apps > Learn > Metro style app reference > Language reference for Metro style apps > Visual C++ reference for Windows Runtime > collection.hWindows::Foundation::Collections Namespace (C++/CX)にリファレンスがあります。今回登場しませんでしたが、IVector<>に対するbegin/end(ランダムアクセスイテレータを返す)などがあります。
2015年5月5日追記:MSDNライブラリのcollection.hがリンク切れとなったので、同等と思われるWindows::Foundation::Collections Namespaceへのリンクを追加しました
スポンサード リンク |