C++20 with u8, char8_t and std::string

C++20 with u8, char8_t and std::string

本文关键字:and std string with u8 char8 C++20      更新时间:2023-10-16

c 11为我们带来了UTF-8文字的U8前缀,我认为几年前很酷,并用类似的东西给我的代码撒了下来:

std::string myString = u8"●";

这一切都很好,但是问题出现在C 20中,它似乎不再编译了,因为U8创建了一个char8_t*,这与仅使用char的STD :: String不兼容。p>我应该创建一个新的UTF8String吗?在C 20世界中,一致和正确的方法是什么,我们有更多的显式类型与标准STD :: String不匹配?

除了 @lubgr的答案外,纸char8_t向后兼容性补救(P1423(讨论了如何使用char8_t字符数组制作std::string的几种方法。

基本上的想法是,您可以将u8 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

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

no,C 20添加std::u8string。但是,我建议使用std::string,因为char8_t在标准中受支持的支持很差,并且根本不受任何系统API的支持(并且可能永远不会因为兼容原因(。在大多数平台上,普通char字符串已经是UTF-8,在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

在带有MSVC和PER-C 20的Windows上,情况甚至更糟,因为U8字符串可能会被静默损坏。例如:

std::cout << "Привет, мир!n";

将产生有效的UTF-8,该UTF-8可能会根据当前代码页面显示在控制台中时,

std::cout << u8"Привет, мир!n";

几乎肯定会给您带来无效的结果,例如╨а╤Я╨б╨В╨а╤С╨а╨Ж╨а┬╡╨бтАЪ, ╨а╤Ш╨а╤С╨б╨В!

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

不,它已经在那里。P0482不仅提出了char8_t,而且还提出了std::basic_string的新专业化char8_t字符类型,名为std::u8string。因此,这已经使用TRUNK中的clanglibc++编译:

const std::u8string str = u8"●";

std::string u8-文字断裂的构造是不幸的。从提案中:

此提案没有指定除保留其弃用界面外的任何向后兼容性功能。作者认为这种功能是必要的,但是一组此类功能会不必要地损害该提案的目标。相反,期望实施将提供选项以启用更多细性粒度兼容性功能。

但我想大多数以上的初始化应该是 grep-可供某些自动clang工具修复。

当前看起来像在总线下,倡导者的UTF8无处不在,C 20提供又有缺陷的不完整选项,可以考虑如何处理如何处理Portable Code的字符编码。char8_t进一步弄乱了一些已经很脏的水。我能够提出的最好的方法是使用MSVC OptionPreview的停止差距 - 最新的C 工作草稿(/STD:C 最新(的功能是...

#if defined(__cpp_char8_t)
template<typename T>
const char* u8Cpp20(T&& t) noexcept 
{ 
#pragma warning (disable: 26490)
   return reinterpret_cast<const char*>(t);
#pragma warning (default: 26490)
}
   #define U8(x) u8Cpp20(u8##x)
#else
   #define U8(x) u8##x
#endif

这很丑陋,效率低下且令人讨厌。但是它允许替换所有U8"用u8" quot"在传统的"无处不在"代码中。我计划避开char8_t,直到产品更加连贯和完整(或永远(。我们应该拭目以待,看看C 20最终达到了什么。目前,char8_t令人失望。

如果有人有兴趣,我在GitHub(对于Visual Studio社区(上发布了我自己的UTF8响应的开源示例。https://github.com/jackheeley/app3dev

将使用U8文字用作const char*的另一种方法将是用户定义的文字(请参阅https://en.cppreference.com/w/cpp/langueage/user_literal(:

std::string operator"" S(const char8_t* str, std::size_t) {
    return reinterpret_cast< const char* >(str);
}
char const* operator"" C(const char8_t* str, std::size_t) {
    return reinterpret_cast< const char* >(str);
}

用法:然后可以像这样使用:

std::string myString = u8"●"S;

SetConsoleOutputCP(CP_UTF8);
std::cout << u8"Привет, мир!"C << std::endl;

说明

上面的代码定义了两个用户定义的文字u8"…"Su8"…"C(请记住:C 20中的文字u8"…"const char8_t*类型(。S文字创建了std::stringC字面创建const char *

这意味着u8"…"C表格的所有文字都可以像"…"文字一样使用,而u8"…"S表格的所有文字都可以像"…"s文字一样使用。

ps:我不确定,如果允许它定义不在台下" _"的文字。但是,当我在Visual Studio中尝试时,代码没有问题。但是cppreference中的所有示例均为下划线。

可能不方便,但您使用此信息: (const char*)u8"こんにちは"

或用参数制作2个函数" const char*&quot"and&quot" const char8_t*&quot"