我尝试使用Visual C++ 2022版本17.4.4(C++标准设置为最新)打印Unicode字符。
#include <iostream>
using namespace std;
int main()
{
cout << u8"The official vowels in Danish are: a, e, i, o, u, \u00E6, \u00F8, \u00E5 and y.\n";
return 0;
}
我有编译错误:
1>C:\projects\cpp\test\test.cpp(7,8): error C2280: 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const char8_t *)': attempting to reference a deleted function
1>C:\projects\cpp\test\test.cpp(7,8): error C2088: '<<': illegal for class
对于u
(utf-16)和U
(utf-32)字符串常量也观察到相同的行为。
将标准设置为C17或C14使程序可以编译。
在C++20和更高的标准中不允许这种代码的理由是什么?在这些标准中打印Unicode字符串字面量的正确方法是什么?
2条答案
按热度按时间dgiusagp1#
在C20之前,
u8"..."
是const char[N]
。从C20开始,它现在是const char8_t[N]
。std::cout
是一个std::basic_ostream<char>
,因此自C++20起不能输出char8_t
数据。可能的work around:
zysjyyx42#
C20中不允许使用此代码的理由是什么
首先,在C20以前的版本中,没有
char8_t
类型,u8
前缀只会产生char
数据,同时影响其编码。C20在p0482中引入了
char8_t
,并向后不兼容地改变了u8
前缀以产生char8_t
数据。但是,正如p1423所指出的,这引入了一个无声的、适得其反的行为变化,而建议的解决方案是使操作变成病态的:
P0482R6的采用引入了一个非预期的静态行为变化。在C17中,以下代码将文字的代码单元写入stdout。在C++20中,此代码现在将字符文字作为数字写入stdout,并将字符串文字的地址写入stdout。
这是一个令人惊讶的变化,对程序员没有任何好处。添加删除的ostream插入器可以避免这种令人惊讶的行为变化,同时保留将来为这些操作指定行为的可能性(例如,指定隐式代码转换为执行编码)。
在那些标准中打印Unicode字符串文字的正确方法是什么?
从C++20开始,还没有定义任何标准的方法来直接将
char8_t
,char16_t
或char32_t
打印为文本。你必须将Unicode数据转换为char
或wchar_t
使用的本地编码,然后打印它。尽管没有标准的方法来做这样的转换(不反对)。Unicode字符类型通常对写入文件有用,但对写入标准输出不太有用。