Поделиться через


Стандартные типы данных 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