Penanganan string di C++/WinRT

Dengan C++/WinRT, Anda dapat memanggil API Windows Runtime menggunakan jenis string lebar Pustaka Standar C++ seperti std::wstring (catatan: tidak dengan jenis string sempit seperti std::string). C++/WinRT memang memiliki jenis string kustom yang disebut winrt::hstring (didefinisikan dalam pustaka dasar C++/WinRT, yaitu %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h). Dan itulah tipe string yang benar-benar diterima dan dikembalikan oleh konstruktor, fungsi, dan properti Windows Runtime. Tetapi dalam banyak kasus—berkat konstring konversi dan operator konversi hstring—Anda dapat memilih apakah akan mengetahui hstring dalam kode klien Anda atau tidak. Jika Anda menulis API, maka Anda lebih mungkin perlu mengetahui tentang hstring.

Ada banyak jenis string di C++. Varian ada di banyak pustaka selain std::basic_string dari Pustaka Standar C++. C++17 memiliki utilitas konversi string, dan std::basic_string_view, untuk menjenjangkan kesenjangan di antara semua jenis string. winrt::hstring dapat dikonversi ke std::wstring_view untuk menyediakan interoperabilitas yang memang dirancang untuk std::basic_string_view.

Menggunakan std::wstring (dan secara opsional winrt::hstring) dengan Uri

Windows::Foundation::Uri dibangun dari winrt::hstring.

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

Tetapi hstring memiliki konstruktor konversi yang memungkinkan Anda bekerja dengannya tanpa perlu menyadarinya. Berikut adalah contoh kode yang menunjukkan cara membuat Uri dari literal string lebar, dari tampilan string yang luas, dan dari 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 };
}

Aksesor properti Uri::Domain bertipe hstring.

public:
    winrt::hstring Domain();

Tapi, sekali lagi, menyadari detail itu bersifat opsional berkat operator konversi hstringke 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"

Demikian pula, IStringable::ToString mengembalikan hstring.

public:
    hstring ToString() const;

Uri mengimplementasikan antarmuka 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/"

Anda dapat menggunakan fungsi hstring::c_str untuk mendapatkan string lebar standar dari hstring (seperti yang Anda bisa dari std::wstring).

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

Jika Anda memiliki hstring maka Anda dapat membuat Uri darinya.

Uri awUriFromHstring{ tostringHstring };

Pertimbangkan metode yang mengambil hstring.

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

Semua opsi yang baru saja Anda lihat juga berlaku dalam kasus seperti itu.

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

hstring memiliki operator konversi anggota std::wstring_view , dan konversi dicapai tanpa biaya.

void legacy_print(std::wstring_view view);

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

winrt::hstring fungsi dan operator

Sejumlah konstruktor, operator, fungsi, dan iterator diimplementasikan untuk winrt::hstring.

hstring merupakan sebuah rentang, sehingga Anda dapat menggunakannya dengan for berbasis rentang, atau dengan std::for_each. Ini juga menyediakan operator perbandingan untuk membandingkan secara alami dan efisien dengan rekan-rekannya di Pustaka Standar C++. Dan itu termasuk semua yang Anda butuhkan untuk menggunakan hstring sebagai kunci untuk kontainer asosiatif.

Kami mengenali bahwa banyak pustaka C++ menggunakan std::string, dan bekerja secara eksklusif dengan teks UTF-8. Sebagai kenyamanan, kami menyediakan pembantu, seperti winrt::to_string dan winrt::to_hstring, untuk mengonversi bolak-balik.

WINRT_ASSERT adalah definisi makro, dan meluas ke _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!");

Untuk contoh dan info selengkapnya tentang fungsi dan operator hstring , lihat topik referensi API winrt::hstring .

Alasan untuk winrt::hstring dan winrt::param::hstring

Windows Runtime diimplementasikan menggunakan karakter wchar_t, tetapi Application Binary Interface (ABI) Windows Runtime bukan merupakan subset dari yang disediakan oleh std::wstring maupun std::wstring_view. Menggunakannya akan menyebabkan inefisiensi yang signifikan. Sebagai gantinya, C++/WinRT menyediakan winrt::hstring, yang merepresentasikan string yang tidak dapat diubah dan konsisten dengan HSTRING yang mendasarinya, serta diimplementasikan melalui antarmuka yang mirip dengan std::wstring.

Anda mungkin memperhatikan bahwa parameter input C++/WinRT yang secara logis seharusnya menerima winrt::hstring ternyata mengharapkan winrt::param::hstring. Namespace param berisi sekumpulan tipe yang digunakan khusus untuk mengoptimalkan parameter input agar dapat terikat secara alami ke tipe dalam Pustaka Standar C++ dan menghindari penyalinan serta inefisiensi lainnya. Anda tidak boleh menggunakan jenis ini secara langsung. Jika Anda ingin menggunakan pengoptimalan untuk fungsi Anda sendiri, gunakan std::wstring_view. Lihat juga Meneruskan parameter ke dalam batas ABI.

Intinya adalah bahwa Anda sebagian besar dapat mengabaikan seluk-beluk pengelolaan string Windows Runtime, dan cukup bekerja secara efisien dengan apa yang sudah Anda ketahui. Dan itu penting, mengingat string banyak digunakan dalam Windows Runtime.

Pemformatan string

Salah satu opsi untuk pemformatan string adalah std::wostringstream. Berikut adalah contoh yang memformat dan menampilkan pesan pelacakan debug sederhana.

#include <sstream>
#include <winrt/Microsoft.UI.Input.h>
#include <winrt/Microsoft.UI.Xaml.Input.h>
...
void MainPage::OnPointerPressed(winrt::Microsoft::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());
}

Cara yang benar untuk menyetel properti

Anda mengatur properti dengan meneruskan nilai ke fungsi setter. Berikut ini contohnya.

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

Kode di bawah ini salah. Kode ini dapat dikompilasi, tetapi yang dilakukannya hanyalah memodifikasi winrt::hstring sementara yang dikembalikan oleh fungsi akses Text(), lalu hasilnya dibuang.

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

API penting