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


Обработка строк в C++/WinRT

С помощью C++/WinRT можно вызывать API среды выполнения Windows с помощью типов строк стандартной библиотеки C++, таких как std::wstring (примечание: не с узкими типами строк, такими как std::string). C++/WinRT имеет настраиваемый тип строки с именем winrt::hstring (определенный в базовой библиотеке C++/WinRT).%WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h И это строковый тип, который конструкторы, функции и свойства среды выполнения Windows фактически принимают и возвращают. Во многих случаях — благодаря конструкторам преобразования и операторам преобразования hstring— можно решить, нужно ли учитывать hstring в клиентском коде. Если вы разработку API, то вам, скорее всего, потребуется знать о hstring.

В C++существует множество типов строк. Варианты существуют во многих библиотеках в дополнение к std::basic_string из стандартной библиотеки C++. C++17 содержит служебные программы преобразования строк и std::basic_string_view, чтобы преодолеть пробелы между всеми типами строк. winrt::hstring обеспечивает совместимость с std::wstring_view для взаимодействия, ради которого был разработан std::basic_string_view.

Использование std::wstring (и при необходимости winrt::hstring) с URI

Windows::Foundation::Uri создается из winrt::hstring.

public:
    Uri(winrt::hstring uri) const;

Но hstring имеет конструкторы преобразования, которые позволяют работать с ним без необходимости учитывать его. Ниже приведен пример кода, показывающий, как создать URI из широкого строкового литерала, из представления широкой строки и из std::wstring.

#include <winrt/Windows.Foundation.h>
#include <string_view>

using namespace winrt;
using namespace Windows::Foundation;

int main()
{
    using namespace std::literals;

    winrt::init_apartment();

    // You can make a Uri from a wide string literal.
    Uri contosoUri{ L"http://www.contoso.com" };

    // Or from a wide string view.
    Uri contosoSVUri{ L"http://www.contoso.com"sv };

    // Or from a std::wstring.
    std::wstring wideString{ L"http://www.adventure-works.com" };
    Uri awUri{ wideString };
}

Метод доступа к свойствам Uri::Domain имеет тип hstring.

public:
    winrt::hstring Domain();

Но знание этой детали, опять же, необязательно благодаря оператора преобразованияв std::wstring_view.

// Access a property of type hstring, via a conversion operator to a standard type.
std::wstring domainWstring{ contosoUri.Domain() }; // L"contoso.com"
domainWstring = awUri.Domain(); // L"adventure-works.com"

// Or, you can choose to keep the hstring unconverted.
hstring domainHstring{ contosoUri.Domain() }; // L"contoso.com"
domainHstring = awUri.Domain(); // L"adventure-works.com"

Аналогичным образом IStringable::ToString возвращает hstring .

public:
    hstring ToString() const;

URI реализует интерфейс IStringable.

// Access hstring's IStringable::ToString, via a conversion operator to a standard type.
std::wstring tostringWstring{ contosoUri.ToString() }; // L"http://www.contoso.com/"
tostringWstring = awUri.ToString(); // L"http://www.adventure-works.com/"

// Or you can choose to keep the hstring unconverted.
hstring tostringHstring{ contosoUri.ToString() }; // L"http://www.contoso.com/"
tostringHstring = awUri.ToString(); // L"http://www.adventure-works.com/"

Функцию hstring::c_str можно использовать для получения стандартной широкой строки из hstring (так же, как и из std::wstring).

#include <iostream>
std::wcout << tostringHstring.c_str() << std::endl;

Если у вас есть hstring, тогда вы можете создать из него Uri.

Uri awUriFromHstring{ tostringHstring };

Рассмотрим метод, который принимает hstring.

public:
    Uri CombineUri(winrt::hstring relativeUri) const;

Все варианты, которые вы только что видели, также применяются в таких случаях.

std::wstring contact{ L"contact" };
contosoUri = contosoUri.CombineUri(contact);
    
std::wcout << contosoUri.ToString().c_str() << std::endl;

hstring имеет оператор преобразования std::wstring_view, а преобразование выполняется без затрат.

void legacy_print(std::wstring_view view);

void Print(winrt::hstring const& hstring)
{
    legacy_print(hstring);
}

winrt::hstring функции и операторы

Для winrt::hstring реализовано множество конструкторов, операторов, функций и итераторов.

hstring — это диапазон, поэтому его можно использовать в конструкциях, работающих с диапазонами, таких как , или совместно с . Он также предоставляет операторы сравнения для естественного и эффективного сравнения со своими коллегами в стандартной библиотеке C++. Он включает в себя все, что необходимо, чтобы использовать hstring в качестве ключа для ассоциативных контейнеров.

Мы понимаем, что многие библиотеки C++ используют std::string и работают исключительно с текстом UTF-8. В качестве удобства мы предоставляем вспомогатели, такие как winrt::to_string и winrt::to_hstring, для преобразования в обоих направлениях.

WINRT_ASSERT — это определение макроса, и оно расширяется до _ASSERTE.

winrt::hstring w{ L"Hello, World!" };

std::string c = winrt::to_string(w);
WINRT_ASSERT(c == "Hello, World!");

w = winrt::to_hstring(c);
WINRT_ASSERT(w == L"Hello, World!");

Дополнительные примеры и сведения о функциях и операторах hstring см. в справочном разделе по API winrt::hstring .

Обоснование winrt::hstring и winrt::param::hstring

Среда выполнения Windows реализована на основе символов wchar_t, но двоичный интерфейс приложения среды выполнения Windows (ABI) не является подмножеством того, что предоставляют std::wstring или std::wstring_view. Использование этих данных приведет к значительной неэффективности. Вместо этого C++/WinRT предоставляет winrt::hstring, который представляет неизменяемую строку, согласованную с базовым HSTRING, и реализован через интерфейс, аналогичный интерфейсу std::wstring.

Вы можете заметить, что входные параметры C++/WinRT, которые логически должны принимать winrt::hstring, на самом деле ожидают winrt::param::hstring. Пространство имен param содержит набор типов, используемых исключительно для оптимизации входных параметров, чтобы естественно привязаться к типам стандартной библиотеки C++ и избежать копирования и других неэффективностей. Не следует использовать эти типы напрямую. Если вы хотите использовать оптимизацию для собственных функций, используйте std::wstring_view. См. также передачу параметров через границу ABI.

Вы можете игнорировать в значительной степени особенности управления строками среды выполнения Windows и просто работать эффективно с тем, что вы знаете. И это важно, учитывая, насколько сильно строки используются в среде выполнения Windows.

Форматирование строк

Одним из вариантов форматирования строк является std::wostringstream. Ниже приведен пример форматирования и отображения простого сообщения трассировки отладки.

#include <sstream>
#include <winrt/Windows.UI.Input.h>
#include <winrt/Windows.UI.Xaml.Input.h>
...
void MainPage::OnPointerPressed(winrt::Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e)
{
    winrt::Windows::Foundation::Point const point{ e.GetCurrentPoint(nullptr).Position() };
    std::wostringstream wostringstream;
    wostringstream << L"Pointer pressed at (" << point.X << L"," << point.Y << L")" << std::endl;
    ::OutputDebugString(wostringstream.str().c_str());
}

Правильный способ задать свойство

Свойство задается путем передачи значения функции задания. Вот пример.

// The right way to set the Text property.
myTextBlock.Text(L"Hello!");

Приведенный ниже код является неверным. Он компилируется, но все, что он делает, — это изменяет временную winrt::hstring, возвращаемую функцией доступа Text(), а затем просто отбрасывает результат.

// *Not* the right way to set the Text property.
myTextBlock.Text() = L"Hello!";

Важные API