为什么在较新的C++标准中,使用cout打印unicode编码字符串会导致编译错误?

biswetbf  于 2023-02-06  发布在  其他
关注(0)|答案(2)|浏览(245)

我尝试使用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字符串字面量的正确方法是什么?

dgiusagp

dgiusagp1#

在C20之前,u8"..."const char[N]。从C20开始,它现在是const char8_t[N]
std::cout是一个std::basic_ostream<char>,因此自C++20起不能输出char8_t数据。
可能的work around

std::basic_ostream<char>& operator<<(std::basic_ostream<char>& cout, const char8_t* s) {
  cout << reinterpret_cast<const char*>(s);
  return cout;
}

// Output: The official vowels in Danish are: a, e, i, o, u, æ, ø, å and y.
zysjyyx4

zysjyyx42#

C20中不允许使用此代码的理由是什么
首先,在C
20以前的版本中,没有char8_t类型,u8前缀只会产生char数据,同时影响其编码。
C20在p0482中引入了char8_t,并向后不兼容地改变了u8前缀以产生char8_t数据。
但是,正如p1423所指出的,这引入了一个无声的、适得其反的行为变化,而建议的解决方案是使操作变成病态的:
P0482R6的采用引入了一个非预期的静态行为变化。在C
17中,以下代码将文字的代码单元写入stdout。在C++20中,此代码现在将字符文字作为数字写入stdout,并将字符串文字的地址写入stdout。

std::cout << u8'x';    // In C++20, writes the number 120.
std::cout << u8"text"; // In C++20, writes a memory address.

这是一个令人惊讶的变化,对程序员没有任何好处。添加删除的ostream插入器可以避免这种令人惊讶的行为变化,同时保留将来为这些操作指定行为的可能性(例如,指定隐式代码转换为执行编码)。
在那些标准中打印Unicode字符串文字的正确方法是什么?
从C++20开始,还没有定义任何标准的方法来直接将char8_tchar16_tchar32_t打印为文本。你必须将Unicode数据转换为charwchar_t使用的本地编码,然后打印它。尽管没有标准的方法来做这样的转换(不反对)。
Unicode字符类型通常对写入文件有用,但对写入标准输出不太有用。

相关问题