如何在 C++20 中安全地将常量字符* 转换为常量 char8_t*?

How to safely convert const char* to const char8_t* in C++20?

本文关键字:常量 转换 char8 字符 C++20 安全      更新时间:2023-10-16

从这个答案中我了解到,在 C++17 中,我们可以通过std::filesystem::u8path使用 UTF-8 路径打开std::fstream。但是在 C++20 中,这个函数被弃用了,我们应该const char8_t*传递给std::filesystem::path构造函数。

问题来了:虽然我们可以合法地转换(通过reinterpret_cast(任何指向const char*的指针,但我们不能向后:从const char*到例如const char8_t*(它会破坏严格的别名规则(。因此,如果我们有一些外部 API 返回文件名的基于char的 UTF-8 表示形式(例如,来自用 C 编写的库(,我们无法安全地将指针转换为基于char8_t的指针。

那么,我们应该如何将这种基于charUTF-8 字符串的视图转换为基于char8_t的视图呢?

免责声明:我是 P0482 提案的作者,该提案引入了char8_t并弃用了u8path

您的观察是正确的;不允许使用reinterpret_cast来生成指向char对象序列的char8_t指针。 这将在 https://stackoverflow.com/a/57453713/11634221 中进一步讨论。

虽然std::filesystem::u8path已在 C++20 年弃用,但没有计划立即将其删除;您可以继续使用它。 此外,P1423纠正了P0482变化的意外后果,并允许在C++20中以charchar8_t的范围调用它。 据我所知,没有实现者将std::filesystem::u8path注释为已弃用(我不知道是否有任何计划这样做(。

没有(格式良好的(方法来生成基于char8_t指针的char序列视图。 可以编写一个范围/迭代器适配器,该适配器在内部将单个char值转换为迭代器取消引用时的char8_t。 此类适配器可以满足不可变迭代器的 C++17 和 C++20 随机访问迭代器要求(它不能满足可变迭代器的要求,因为取消引用操作无法提供左值,也无法满足连续迭代器的要求(。 这样的适配器足以调用接受范围的std::filesystem::path构造函数。 嗯,这可能是一个足够有用的适配器,可以添加到 https://github.com/tahonermann/char8_t-remediation。

当然,对基础char数据视图的替代方法是复制它,但我可以理解为什么这样做可能被认为是不可取的(我们在使用std::filesystem::path时已经倾向于进行大量复制(。

从这个字符类型参考关于char8_t

它具有与unsigned char相同的大小、符号和对齐方式(因此,与charsigned char相同的大小和对齐方式(,但是一种不同的类型。

因为它是一种独特的类型,所以您无法在不破坏严格混叠的情况下从const char*转换为const char8_t*。但出于所有实际目的,由于char8_t基本上是一个unsigned char您可以使用reinterpret_cast来转换指针。这是错误的,但会起作用。

为了正确起见,请使用char8_t开头,或将原始字符复制到char8_t缓冲区(或std::u8string(。