文字列がある場合:
std::string s = u8"你好";
そしてC++ 20では、
std::u8string s = u8"你好";
std::u8string
はstd::string
とどのように異なりますか?
u8string
とstring
の違いは、1つはchar8_t
でテンプレート化され、もう1つはchar
でテンプレート化されるということなので、real質問は、char8_t
ベースの文字列とchar
ベースの文字列の使用の違いは何ですか。
それは本当にこれに帰着します:タイプベースのエンコーディング。
char
ベースの文字列(char*
、char[]
、string
など)は、UTF-8でエンコードできます。しかし、再び、それはできません。 char*
に相当するものはすべてUTF-8でエンコードされることを想定して、コードを開発できます。また、すべての文字列リテラルの前にu8
を記述したり、適切にエンコードされていることを確認したりできます。だが:
他の人のコードは同意しないかもしれません。そのため、UTF-8エンコーディングを使用しないchar*
sを返す可能性のあるライブラリは使用できません。
誤って自分の教訓に違反する可能性があります。結局のところ、char not_utf8[] = "你好";
は条件付きでサポートされるC++です。そのchar[]
のエンコーディングは、コンパイラの狭いエンコーディングになります...が何であっても。一部のコンパイラではUTF-8になり、他のコンパイラではUTF-8になる場合があります。
これがあなたがやっていることを他の人のコード(またはチームの他の人)に伝えることはできません。つまり、APIは特定のchar*
がUTF-8でエンコードされていることを宣言できません。これは、ユーザーがコードで見るものではなく、ユーザーが想定している、またはドキュメントで別の方法で読んだものでなければなりません。
これらの問題は、UTF-16またはUTF-32のユーザーには存在しないことに注意してください。 char16_t
ベースの文字列を使用すると、これらの問題はすべてなくなります。他の人のコードがchar16_t
文字列を返す場合、彼らは何をしているのかわかります。それらが別のものを返す場合、それらはおそらくUTF-16ではないことがわかります。 UTF-16ベースのコードは、それらと相互運用できます。 char16_t
ベースの文字列を返すAPIを作成すると、コードを使用しているすべての人が、文字列のタイプからそれがどのエンコーディングであるかを確認できます。そして、これはコンパイルエラーであることが保証されています: `char16_t not_utf16 [] ="你好 ";
今はそうです、これらの事柄の保証はありません。特定のchar16_t
文字列には、UTF-16で不正な値であっても、値が含まれている可能性があります。ただし、char16_t
は、デフォルトの想定が特定のエンコーディングであるタイプを表します。それを考えると、UTF-16エンコードされていないこのタイプの文字列を提示する場合、これをユーザーによる間違い/改ざんと見なすことは不合理ではなく、それは契約違反であると考えられます。
UTF-8に同様のタイプベースの機能がないことにより、C++がどのように影響を受けたかがわかります。 filesystem::path
を検討してください。 Unicodeエンコーディングの文字列をとることができます。 UTF-16/32の場合、path
のコンストラクターはchar16/32_t
ベースの文字列を取ります。ただし、UTF-8文字列をpath
のコンストラクターに渡すことはできません。 char
ベースのコンストラクタは、エンコーディングがUTF-8ではなく、実装定義のナローエンコーディングであることを前提としています。したがって、代わりにfilesystem::u8path
を使用する必要があります。これは、UTFから構築されたpath
を返す独立した関数です-8エンコードされた文字列。
さらに悪いことに、UTF-8でエンコードされたchar
ベースの文字列をpath
のコンストラクターに渡そうとすると、正常にコンパイルされます。せいぜいポータブルではありませんが、機能しているように見えます。
char8_t
、およびu8string
などのすべての付属品は、UTF-8ユーザーが他のUTFエンコーディングと同じ能力を使用できるようにするために存在します。 C++ 20では、filesystem::path
はchar8_t
ベースの文字列のオーバーロードを取得し、 u8path
は廃止されます。
また、追加のボーナスとして、char8_t
には特別なエイリアス言語がありません。したがって、char8_t
ベースの文字列を受け取るAPIは、確かに任意のバイト配列ではなく、文字配列を受け取るAPIです。