如果我有一个字符串:
std::string s = u8"你好";
和C ++ 20中的
std::u8string s = u8"你好";
std::u8string
与std::string
有何不同?
答案 0 :(得分:7)
由于u8string
和string
之间的区别在于,一个是在char8_t
上模板化的,另一个是在char
上模板化的,所以 real 问题是使用基于char8_t
的字符串与基于char
的字符串有什么区别。
这实际上归结为:基于类型的编码。
任何基于char
的字符串(char*
,char[]
,string
等)都可以用UTF-8编码。但话又说回来,可能不是。您可以假设每个等效的char*
都将以UTF-8编码的方式来开发代码。您可以在每个字符串文字前写一个u8
和/或以其他方式确保它们已正确编码。但是:
其他人的代码可能不同意。因此,您不能使用任何可能返回不使用UTF-8编码的char*
的库。
您可能不小心违反了自己的戒律。毕竟,char not_utf8[] = "你好";
是有条件支持的C ++。 char[]
的编码将是编译器的窄编码……无论该 是什么。在某些编译器上可能是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-8编码的字符串构造的path
。
更糟糕的是,如果您尝试将基于UTF-8编码的基于char
的字符串传递给path
的构造函数……它可以很好地编译。尽管充其量是不可移植的,但它似乎还是可以工作的。
char8_t
及其所有类似u8string
的附件的存在是为了允许UTF-8用户获得与其他UTF编码相同的功能。在C ++ 20中,filesystem::path
将基于char8_t
的字符串和u8path
will become obsolete.
此外,char8_t
并没有特殊的别名语言。因此,采用char8_t
为基础的字符串的API 肯定是采用字符数组而不是任意字节数组的API。