Стандартные типы данных C++ и C++/WinRT
С помощью C++/WinRT можно вызывать интерфейсы API среды выполнения Windows с использованием стандартных типов данных C++, включая некоторые типы данных стандартной библиотеки C++. Вы можете передать стандартные строки в интерфейсы API (см. раздел Обработка строк в C++/WinRT), вы можете также передать списки инициализатора и стандартные контейнеры в интерфейсы API, ожидающие семантически эквивалентную коллекцию.
Также см. статью о передаче параметров в интерфейс ABI.
Стандартные списки инициализатора
Список инициализатора (std::initializer_list) — это конструкция стандартной библиотеки C++. Списки инициализатора можно использовать при вызове определенных конструкторов и методов среды выполнения Windows. Например, с помощью одного из них можно вызвать DataWriter::WriteBytes.
#include <winrt/Windows.Storage.Streams.h>
using namespace winrt::Windows::Storage::Streams;
int main()
{
winrt::init_apartment();
InMemoryRandomAccessStream stream;
DataWriter dataWriter{stream};
dataWriter.WriteBytes({ 99, 98, 97 }); // the initializer list is converted to a winrt::array_view before being passed to WriteBytes.
}
Это работает благодаря двум элементам. Во-первых, метод DataWriter::WriteBytes принимает параметр типа winrt::array_view.
void WriteBytes(winrt::array_view<uint8_t const> value) const
winrt::array_view является настраиваемым типом C++/WinRT, который безопасно представляет непрерывный ряд значений (он определен в базовой библиотеке C++/WinRT — %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h
).
Во-вторых, winrt::array_view имеет конструктор списков инициализатора.
template <typename T> winrt::array_view(std::initializer_list<T> value) noexcept
Во многих случаях вы можете выбрать, учитывать ли winrt::array_view при программировании. Если вы решите не учитывать array_view, то у вас не будет кода, требующего изменений, если эквивалентный тип появится в стандартной библиотеке C++.
Вы можете передать список инициализатора в API среды выполнения Windows, который ожидает параметр коллекции. Возьмем, например, StorageItemContentProperties::RetrievePropertiesAsync.
IAsyncOperation<IMap<winrt::hstring, IInspectable>> StorageItemContentProperties::RetrievePropertiesAsync(IIterable<winrt::hstring> propertiesToRetrieve) const;
Вы можете вызвать этот API с помощью списка инициализатора следующим образом.
IAsyncAction retrieve_properties_async(StorageFile const storageFile)
{
auto properties{ co_await storageFile.Properties().RetrievePropertiesAsync({ L"System.ItemUrl" }) };
}
Здесь действуют два фактора. Во-первых, вызываемый создает std::vector из списка инициализатора (это асинхронный вызываемый, поэтому он способен владеть этим объектом, что необходимо). Во-вторых, C++/WinRT прозрачно (и без создания копий) привязывает std::vector в качестве параметра коллекции среды выполнения Windows.
Стандартные массивы и векторы
У winrt::array_view также имеются конструкторы преобразования из std::vector и std::array.
template <typename C, size_type N> winrt::array_view(std::array<C, N>& value) noexcept
template <typename C> winrt::array_view(std::vector<C>& vectorValue) noexcept
Таким образом, можно вместо этого вызвать DataWriter::WriteBytes с помощью std::vector.
std::vector<byte> theVector{ 99, 98, 97 };
dataWriter.WriteBytes(theVector); // theVector is converted to a winrt::array_view before being passed to WriteBytes.
Можно также использовать std::array.
std::array<byte, 3> theArray{ 99, 98, 97 };
dataWriter.WriteBytes(theArray); // theArray is converted to a winrt::array_view before being passed to WriteBytes.
C++/WinRT привязывает std::vector в качестве параметра коллекции среды выполнения Windows. Таким образом, можно передать std::vector<winrt::hstring>, и он будет преобразован в соответствующую коллекцию среды выполнения Windows типа winrt::hstring. Есть еще кое-что, о чем нужно помнить, если используется асинхронный вызываемый. Из-за особенностей реализации этого варианта нужно предоставить rvalue, поэтому необходимо обеспечить копирование или перемещение вектора. В следующем примере кода мы переместим владение вектором на объект с типом параметров, принимаемым асинхронным вызываемым (и затем мы проявим осторожность, чтобы не обратиться к vecH
еще раз после перемещения). Если вы хотите узнать больше о значениях rvalue, ознакомьтесь с разделом Категории значений и ссылки.
IAsyncAction retrieve_properties_async(StorageFile const storageFile, std::vector<winrt::hstring> vecH)
{
auto properties{ co_await storageFile.Properties().RetrievePropertiesAsync(std::move(vecH)) };
}
При этом нельзя передавать std::vector<std::wstring> там, где требуется коллекция среды выполнения Windows. Это связано с тем, что после преобразования в соответствующую коллекцию среды выполнения Windows std::wstring язык C++ не преобразовывает параметры типов этой коллекции. Следовательно, приведенный ниже пример кода не будет компилироваться (и решением является передача std::vector<winrt::hstring>, как показано выше).
IAsyncAction retrieve_properties_async(StorageFile const storageFile, std::vector<std::wstring> vecW)
{
auto properties{ co_await storageFile.Properties().RetrievePropertiesAsync(std::move(vecW)) }; // error! Can't convert from vector of wstring to async_iterable of hstring.
}
Необработанные массивы и диапазоны указателей
Имея в виду, что эквивалентный тип может появиться в стандартной библиотеке C++ в будущем, можно также работать непосредственно с winrt::array_view, если это необходимо.
У winrt::array_view имеются конструкторы преобразования из необработанных массивов и из диапазона T* (указатели на тип элемента).
using namespace winrt;
...
byte theRawArray[]{ 99, 98, 97 };
array_view<byte const> fromRawArray{ theRawArray };
dataWriter.WriteBytes(fromRawArray); // the winrt::array_view is passed to WriteBytes.
array_view<byte const> fromRange{ theArray.data(), theArray.data() + 2 }; // just the first two elements.
dataWriter.WriteBytes(fromRange); // the winrt::array_view is passed to WriteBytes.
Функции и операторы winrt::array_view
Для winrt::array_view реализован ряд конструкторов, операторов, функций и итераторов. Тип winrt::array_view является диапазоном, поэтому вы можете использовать его с основанным на диапазоне for
или с std::for_each.
Дополнительные примеры и сведения приведены в справочнике по API winrt::array_view.
IVector<T> и стандартные итерационные конструкции
SyndicationFeed.Items является примером API среды выполнения Windows, который возвращает коллекцию типа IVector<T> (проецируемую в C++/WinRT как winrt::Windows::Foundation::Collections::IVector<T>). Можно использовать этот тип со стандартными итерационными конструкциями, такими как for
на основе диапазона.
// main.cpp
#include "pch.h"
#include <winrt/Windows.Web.Syndication.h>
#include <iostream>
using namespace winrt;
using namespace Windows::Web::Syndication;
void PrintFeed(SyndicationFeed const& syndicationFeed)
{
for (SyndicationItem const& syndicationItem : syndicationFeed.Items())
{
std::wcout << syndicationItem.Title().Text().c_str() << std::endl;
}
}
Соподпрограммы C++ с асинхронными интерфейсами API среды выполнения Windows
Вы можете продолжать использовать библиотеки параллельных шаблонов (PPL) при вызове асинхронных API среды выполнения Windows. Тем не менее, во многих случаях соподпрограммы C++ предоставляют эффективную и более удобную для программирования идиому взаимодействия с асинхронными объектами. Дополнительные сведения и примеры кода приведены в разделе Параллельная обработка и асинхронные операции с помощью C++/WinRT.
Важные API
- Интерфейс IVector<T>
- Шаблон структуры winrt::array_view