Стандартные типы данных C++ и C++/WinRT

С помощью C++/WinRT можно вызывать API-интерфейсы среда выполнения Windows с помощью типов данных standard 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 имеет конструктор initializer-list.

template <typename T> winrt::array_view(std::initializer_list<T> value) noexcept

Во многих случаях вы можете выбрать, следует ли учитывать winrt::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 после его перемещения). Если вы хотите узнать больше о rvalues, ознакомьтесь с категориями значений и ссылками на них.

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) при вызове асинхронных среда выполнения Windows API. Однако во многих случаях корутины C++ обеспечивают эффективную и более легко закодированную идиому для взаимодействия с асинхронными объектами. Дополнительные сведения и примеры кода см. в разделе Параллелизм и асинхронные операции с C++/WinRT.

Важные API