自作聪明。
UTF-8 的代码点从来不保证能塞进一个 char_8 里,因此不仅理论上就不可能通过类型系统排除无效代码点,还没有任何真正的防止用错的实际意义:单个 char_8 总是在编码上无意义的,体现不出“确实没有用错”而构成了冗余名义类型;多个 char_8 并无法排除其它现有 UTF-8 的表示反而因为交互困难而容易出错。为了和字符串字面量对应的 u8 字符字面量前缀也体现出这种设计上的不知所谓。
当然这方面的愚蠢向来是传统艺能。
首先应当明确,真正应该排除的是 char 这种莫名其妙的类型——要按字面理解成“字符”,却有算术操作(是不是有符号还不知道);理解成一个字节的整数,又不如 signed char 和 unsigned char 有用(注意 char/signed char/unsigned char 不管表示如何是三种不同的名义类型)。唯一正确了点的设计是 byte ,但因为无法排除现有的 char ,仍然会造成混乱。(虽然 octet 的缺失仍然是问题,但规定 CHAR_BIT >= 8 之后实际编码问题不会那么明显。)
其次类型系统的无能(没有 Perl6 这样的子集限制类型排除非法的值)使合法的编码总是不可能保证完全静态校验。所以加了表示编码的字符串字面量来向非代码作者的读者展示“安全性”多少也是自欺欺人。
第三是 C++20 的笑话:引入 char8_t 要修改 u8 字符串字面量的类型,结果导致了不兼容。提案 P1423R2 显示出有人明显意识到了这个问题,但因为基于代码调查显示出 u8 字符串字面量在之前的使用并不常见,所以接受了不兼容的问题。这个笑话分为两个层次,一是调查基于历史包袱沉重的个别项目;二是设计者不懂类型系统的基本常识,没有意识到 char_8 仍然只是“可能是 UTF-8 字符串的一部分”的半吊子现实,以“继续容易使 UTF-8 和非 UTF-8 字符串混合”为由而拒绝了本应是相对最合理的子类型化 char (允许 char8_t 隐式转换成 char )。结果就是把不兼容的包袱甩给更大不确定的但更能接受新特性的其他用户,凡是之前使用了 u8 字符串字面量的用户就会直接踩坑——就这样还想要用户接受 C++20 ?
UTF-8 的代码点从来不保证能塞进一个 char_8 里,因此不仅理论上就不可能通过类型系统排除无效代码点,还没有任何真正的防止用错的实际意义:单个 char_8 总是在编码上无意义的,体现不出“确实没有用错”而构成了冗余名义类型;多个 char_8 并无法排除其它现有 UTF-8 的表示反而因为交互困难而容易出错。为了和字符串字面量对应的 u8 字符字面量前缀也体现出这种设计上的不知所谓。
当然这方面的愚蠢向来是传统艺能。
首先应当明确,真正应该排除的是 char 这种莫名其妙的类型——要按字面理解成“字符”,却有算术操作(是不是有符号还不知道);理解成一个字节的整数,又不如 signed char 和 unsigned char 有用(注意 char/signed char/unsigned char 不管表示如何是三种不同的名义类型)。唯一正确了点的设计是 byte ,但因为无法排除现有的 char ,仍然会造成混乱。(虽然 octet 的缺失仍然是问题,但规定 CHAR_BIT >= 8 之后实际编码问题不会那么明显。)
其次类型系统的无能(没有 Perl6 这样的子集限制类型排除非法的值)使合法的编码总是不可能保证完全静态校验。所以加了表示编码的字符串字面量来向非代码作者的读者展示“安全性”多少也是自欺欺人。
第三是 C++20 的笑话:引入 char8_t 要修改 u8 字符串字面量的类型,结果导致了不兼容。提案 P1423R2 显示出有人明显意识到了这个问题,但因为基于代码调查显示出 u8 字符串字面量在之前的使用并不常见,所以接受了不兼容的问题。这个笑话分为两个层次,一是调查基于历史包袱沉重的个别项目;二是设计者不懂类型系统的基本常识,没有意识到 char_8 仍然只是“可能是 UTF-8 字符串的一部分”的半吊子现实,以“继续容易使 UTF-8 和非 UTF-8 字符串混合”为由而拒绝了本应是相对最合理的子类型化 char (允许 char8_t 隐式转换成 char )。结果就是把不兼容的包袱甩给更大不确定的但更能接受新特性的其他用户,凡是之前使用了 u8 字符串字面量的用户就会直接踩坑——就这样还想要用户接受 C++20 ?