C++/WinRT의 문자열 처리String handling in C++/WinRT

C++/WinRT에서는 std::wstring 같은 C++ 표준 라이브러리 전각 문자열 형식을 사용해 Windows 런타임 API를 호출할 수 있습니다(참고: std::string 같은 반각 문자열 형식은 사용할 수 없음).With C++/WinRT, you can call Windows Runtime APIs using C++ Standard Library wide string types such as std::wstring (note: not with narrow string types such as std::string). C++/WinRT에는 winrt::hstring이라고 불리는 사용자 지정 문자열 형식이 없습니다(C++/WinRT 기본 라이브러리인 %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h에 정의됨).C++/WinRT does have a custom string type called winrt::hstring (defined in the C++/WinRT base library, which is %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h). 또한 Windows 런타임 생성자, 함수 및 속성이 실제로 가져와 반환하는 문자열 형식이기도 합니다.And that's the string type that Windows Runtime constructors, functions, and properties actually take and return. 하지만 대부분 경우 hstring의 변환 생성자와 변환 연산자 덕분에 클라이언트 코드의 hstring 인식 여부를 선택할 수 있습니다.But in many cases—thanks to hstring's conversion constructors and conversion operators—you can choose whether or not to be aware of hstring in your client code. API를 직접 ‘작성’하는 경우에는 hstring에 대해 알아둘 필요가 더욱 많습니다. If you're authoring APIs, then you're more likely to need to know about hstring.

C++에는 문자열 형식이 많습니다.There are many string types in C++. 또한 C++ 표준 라이브러리의 std::basic_string 외에도 변형된 형식이 여러 라이브러리에 존재합니다.Variants exist in many libraries in addition to std::basic_string from the C++ Standard Library. C++17에는 다양한 문자열 변환 유틸리티를 비롯해 std::basic_string_view도 있기 때문에 모든 문자열 형식의 차이를 좁힐 수 있습니다.C++17 has string conversion utilities, and std::basic_string_view, to bridge the gaps between all of the string types. winrt::hstringstd::basic_string_view가 디자인된 목적인 상호 운용성을 제공하기 위해 std::wstring_view와의 상호 운용성을 제공합니다.winrt::hstring provides convertibility with std::wstring_view to provide the interoperability that std::basic_string_view was designed for.

std::wstring(선택적으로 winrt::hstring)에 Uri 사용Using std::wstring (and optionally winrt::hstring) with Uri

Windows::Foundation::Uriwinrt::hstring에서 생성됩니다.Windows::Foundation::Uri is constructed from a winrt::hstring.

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

하지만 hstring에는 변환 생성자가 있기 때문에 잘 모르더라도 작업하는 데 문제가 없습니다.But hstring has conversion constructors that let you work with it without needing to be aware of it. 다음은 와이드 문자열 리터럴에서, 와이드 문자열 보기에서, 그리고 std::wstring에서 Uri를 생성하는 방법을 나타낸 코드 예제입니다.Here's a code example showing how to make a Uri from a wide string literal, from a wide string view, and from a 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::Domainhstring 형식입니다.The property accessor Uri::Domain is of type hstring.

public:
    winrt::hstring Domain();

다시 얘기하지만 hstring에는 std::wstring_view로 변환할 수 있는 연산자가 있기 때문에 세부 정보를 반드시 알아야 하는 것은 아닙니다.But, again, being aware of that detail is optional thanks to hstring's conversion operator to 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을 반환합니다.Similarly, IStringable::ToString returns hstring.

public:
    hstring ToString() const;

UriIStringable 인터페이스를 구현합니다.Uri implements the IStringable interface.

// 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에서 가져오는 방식과 동일).You can use the hstring::c_str function to get a standard wide string from an hstring (just as you can from a std::wstring).

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

hstring이 있는 경우에는 여기에서 Uri를 생성할 수 있습니다.If you have an hstring then you can make a Uri from it.

Uri awUriFromHstring{ tostringHstring };

hstring을 가져오는 메서드를 고려하세요.Consider a method that takes an hstring.

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

앞에서 방금 보았던 옵션들 역시 모두 이러한 경우에 적용됩니다.All of the options you've just seen also apply in such cases.

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

hstring은 멤버로서 std::wstring_view 변환 연산자가 있기 때문에 아무런 대가 없이 변환이 이루어집니다.hstring has a member std::wstring_view conversion operator, and the conversion is achieved at no cost.

void legacy_print(std::wstring_view view);

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

winrt::hstring 함수와 연산자winrt::hstring functions and operators

winrt::hstring일 때는 다양한 생성자, 연산자, 함수 및 반복기가 구현됩니다.A host of constructors, operators, functions, and iterators are implemented for winrt::hstring.

hstring은 범위이기 때문에 범위 기반 for와 함께, 혹은 std::for_each와 함께 사용할 수 있습니다.An hstring is a range, so you can use it with range-based for, or with std::for_each. 또한 C++ 표준 라이브러리에서 상응하는 항목을 자연스럽게, 그리고 효율적으로 비교할 수 있는 비교 연산자도 제공합니다.It also provides comparison operators for naturally and efficiently comparing against its counterparts in the C++ Standard Library. 여기에는 hstring을 연결 컨테이너의 키로 사용하는 데 필요한 모든 것이 포함됩니다.And it includes everything you need to use hstring as a key for associative containers.

다수의 C++ 라이브러리가 std::string을 사용하며, UTF-8 텍스트에서만 유효하다는 사실은 이미 잘 알고 있습니다.We recognize that many C++ libraries use std::string, and work exclusively with UTF-8 text. 편의상 앞뒤로 변환을 위해 winrt::to_stringwinrt::to_hstring과 같은 도우미를 제공합니다.As a convenience, we provide helpers, such as winrt::to_string and winrt::to_hstring, for converting back and forth.

WINRT_ASSERT는 매크로 정의이며 _ASSERTE로 확장됩니다.WINRT_ASSERT is a macro definition, and it expands to _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 함수 및 연산자에 대한 자세한 예제와 내용은 winrt::hstring API 참조 항목을 참조하세요.For more examples and info about hstring functions and operators, see the winrt::hstring API reference topic.

winrt::hstringwinrt::param::hstring의 이론적 근거The rationale for winrt::hstring and winrt::param::hstring

Windows 런타임은 wchar_t 문자와 관련하여 구현되지만 Windows 런타임의 ABI(Application Binary Interface)는 std::wstring 또는 std::wstring_view가 제공하는 것의 하위 세트가 아닙니다.The Windows Runtime is implemented in terms of wchar_t characters, but the Windows Runtime's Application Binary Interface (ABI) is not a subset of what either std::wstring or std::wstring_view provide. 따라서 이 둘을 사용하면 상당한 비효율성으로 이어질 수 있습니다.Using those would lead to significant inefficiency. 대신 C++/WinRT는 winrt::hstring을 제공합니다. 이는 기본 HSTRING을 따를 뿐만 아니라 std::wstring 인터페이스와 비슷한 인터페이스 뒤에서 구현되기 때문에 문자열을 변경할 수 없다는 것을 의미합니다.Instead, C++/WinRT provides winrt::hstring, which represents an immutable string consistent with the underlying HSTRING, and implemented behind an interface similar to that of std::wstring.

winrt::hstring을 논리적으로 허용해야 하는 C++/WinRT 입력 매개 변수에 실제로 winrt::param::hstring이 필요하다는 사실을 확인할 수 있습니다.You may notice that C++/WinRT input parameters that should logically accept winrt::hstring actually expect winrt::param::hstring. param 네임스페이스에는 C++ 표준 라이브러리 형식에 자연스럽게 바인딩하여 복사본과 기타 비효율성을 회피할 수 있도록 입력 매개 변수를 최적화하는 데만 사용되는 형식 세트만 포함됩니다.The param namespace contains a set of types used exclusively to optimize input parameters to naturally bind to C++ Standard Library types and avoid copies and other inefficiencies. 이 형식을 직접 사용해서는 안 됩니다.You shouldn't use these types directly. 사용자 고유의 함수에 최적화를 사용하려면 std::wstring_view를 사용하세요.If you want to use an optimization for your own functions then use std::wstring_view. 매개 변수를 ABI 경계로 전달도 참조하세요.Also see Passing parameters into the ABI boundary.

결론적으로 Windows 런타임 문자열 관리를 위한 고유 정보는 대부분 무시하고 알고 있는 정보만으로도 효율적으로 작업할 수 있습니다.The upshot is that you can largely ignore the specifics of Windows Runtime string management, and just work with efficiency with what you know. 문자열이 Windows 런타임에서 얼마나 많이 사용되는지 생각해보면 이는 매우 중요합니다.And that's important, given how heavily strings are used in the Windows Runtime.

문자열 형식 지정Formatting strings

문자열 형식을 지정하는 한 가지 옵션은 std::wstringstream입니다.One option for string-formatting is std::wstringstream. 다음은 간단한 디버그 추적 메시지의 형식을 지정하여 표시하는 예제입니다.Here's an example that formats and displays a simple debug trace message.

#include <sstream>
...
void OnPointerPressed(IInspectable const&, PointerEventArgs const& args)
{
    float2 const point = args.CurrentPoint().Position();
    std::wstringstream wstringstream;
    wstringstream << L"Pointer pressed at (" << point.x << L"," << point.y << L")" << std::endl;
    ::OutputDebugString(wstringstream.str().c_str());
}

속성을 설정하는 올바른 방법The correct way to set a property

setter 함수로 값을 전달하여 속성을 설정합니다.You set a property by passing a value to a setter function. 예를 들면 다음과 같습니다.Here's an example.

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

아래는 잘못된 코드입니다.The code below is incorrect. 컴파일할 수는 있지만 Text() 접근자 함수에서 반환된 임시 winrt::hstring을 수정한 다음, 결과를 버리는 것이 전부입니다.It compiles, but all it does is to modify the temporary winrt::hstring returned by the Text() accessor function, and then to throw the result away.

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

중요 APIImportant APIs