具有u8,char8_t和std :: string的C ++ 20

M2t*_*2tM 24 c++ stdstring c++20

C ++ 11给我们带来了UTF-8字面量的u8前缀,几年前我认为这很酷,并在代码中添加了以下内容:

std::string myString = u8"?";
Run Code Online (Sandbox Code Playgroud)

一切都很好,但是在C ++ 20中出现了问题,因为u8创建了char8_t *,并且与仅使用char的std :: string不兼容,因此似乎不再可以编译了。

我应该创建一个新的utf8string吗?在C ++ 20世界中,如果我们有更显式的类型与标准std :: string完全不匹配,那么一致的正确方法是什么?

Fab*_*ssi 15

除了@lubgr的答案外,论文char8_t向后兼容修补(P1423)还讨论了如何std::string使用char8_t字符数组的几种方法。

基本上,您的想法是可以将u8char数组转换为“普通” char数组,以获得与C ++ 17相同的行为,在此之前,您必须更加明确一点。本文讨论了执行此操作的各种方法。

适合您的用例的最简单的方法(但并非完全零开销,除非您添加更多的重载)可能是最后一个方法,即引入显式转换函数:

std::string from_u8string(const std::string &s) {
  return s;
}
std::string from_u8string(std::string &&s) {
  return std::move(s);
}
#if defined(__cpp_lib_char8_t)
std::string from_u8string(const std::u8string &s) {
  return std::string(s.begin(), s.end());
}
#endif
Run Code Online (Sandbox Code Playgroud)

  • 就我而言,最简单的选择似乎是删除所有 `u8"` 的使用,并假设所有 `std::string` 都以 utf8 编码。 (3认同)
  • 这篇论文非常有启发性,我接受这个答案,因为它确实深入到了问题的症结所在,很难选择,因为两个答案都非常有帮助! (2认同)

lub*_*bgr 14

我应该创建一个新的utf8string吗?

不,它已经在那里。P0482不仅提出char8_t了命名类型std::basic_string为的char8_t字符类型,而且提出了一种新的专业化方法std::u8string。因此,这与已经编译clanglibc++从主干:

const std::u8string str = u8"?";
Run Code Online (Sandbox Code Playgroud)

std::stringu8字面意义上进行突破的事实是不幸的。从提案中:

该建议除了保留不赞成使用的接口之外,没有指定任何向后兼容性功能。作者认为这样的功能是必要的,但是这样一组功能将不必要地损害本提案的目标。相反,期望实现将提供选项以启用更细粒度的兼容性功能。

但是我想上面的大多数此类初始化应该是可grep启用的,或者需要进行一些自动clang工具修复。

  • 注意,也可以从litereal推导模板的类型:`std :: basic_string str = u8“●”`。这在C ++ 17和C ++ 20中都可以使用,但是每个版本都具有不同的类型。 (7认同)
  • 哦,现代 C++。你是什​​么样的人。smh (6认同)
  • *“它已经在那里” *-我不会那么乐观,即使`u8string`应该专门处理utf8字符,它仍然将它们视为字节数组而不是符号序列。必须重新实现索引编制和其他每个符号操作,或使用某些第三方字符串。因此,`u8string`与常规`string`相比几乎没有任何好处,特别是如果utf8用于char字符串编码 (4认同)
  • 取得这一点非常重要,任何比这个更大的提议都将很难通过。考虑到我们实际上打破了向后兼容性的记录,这是一个小奇迹。SG16(Unicode /文本研究小组)以此为基础可以立足于 (2认同)
  • 此答案中链接的P0482的修订为初始修订。C ++ 20接受的修订版是[P0482R6](http://wg21.link/p0482),它用以下内容替换了引用的文本:`该提案除了保留其接口之外,不指定任何向后兼容性功能不推荐使用。作者认为这样的功能是必要的,但是这样一组功能将不必要地损害本提案的目标。相反,期望实现将提供选项以启用更细粒度的兼容性功能。 (2认同)

vit*_*aut 9

我应该创建一个新的 utf8string 吗?

不,C++20 添加了std::u8string. 但是,我建议std::string改用它,因为char8_t它在标准中的支持很差,并且根本不受任何系统 API 的支持(并且可能永远不会因为兼容性原因而受到支持)。在大多数平台上,普通char字符串已经是 UTF-8,在带有 MSVC 的 Windows 上,您可以使用/utf-8它进行编译,这将在主要操作系统上为您提供可移植的 Unicode 支持。

例如,您甚至无法在 C++20 中使用 u8 字符串编写 Hello World 程序(https://godbolt.org/z/E6rvj5):

std::cout << u8"Hello, world!\n"; // won't compile in C++20
Run Code Online (Sandbox Code Playgroud)

在使用 MSVC 和 C++20 之前的 Windows 上,情况更糟,因为 u8 字符串可能会被悄悄损坏。例如:

std::cout << "??????, ???!\n";
Run Code Online (Sandbox Code Playgroud)

将产生有效的 UTF-8 可能会或可能不会显示在控制台中,具体取决于其当前代码页,而

std::cout << u8"??????, ???!\n";
Run Code Online (Sandbox Code Playgroud)

几乎肯定会给你一个无效的结果,例如?????????????????????????, ????????????!.

  • MSVC 默默地破坏字符串的说法并不准确。相反,在某些情况下,[mojibake](https://en.wikipedia.org/wiki/Mojibake) 可能会带来令人惊讶的结果。默认情况下,MSVC 使用活动代码页(ACP;例如 Windows-1252)作为源文件的编码。不使用“/source-charset:utf-8”选项编译 UTF-8 源文件将导致文字从 ACP(错误地)转换为目标编码。此外,Windows 控制台(不是 MSVC)将根据其编码(例如 CP437)解释输出,产生如 @vitaut 所示的结果。 (3认同)