iostreams - 将`wchar_t`或`charXX_t`值打印为字符

zwo*_*wol 6 c++ iostream widechar

如果将a wchar_t,char16_tchar32_t值提供给狭窄的ostream,它将打印代码点的数值.

#include <iostream>
using std::cout;
int main()
{
    cout << 'x' << L'x' << u'x' << U'x' << '\n';
}
Run Code Online (Sandbox Code Playgroud)

打印x120120120.这是因为有一个与它operator<<的特定组合,但是对于其他字符类型没有类似的运算符,所以它们以这种方式静默转换和打印.类似地,非窄字符串(,,)将被默默地转换为与打印为指针值,和非窄字符串对象(,,)甚至不会编译.basic_ostreamcharTintL"x"u"x"U"X"void*wstringu16stringu32string

因此,问题:什么是打印最少可怕的方式wchar_t,char16_tchar32_t在一个狭窄的ostream值,作为字符,而不是作为码点的数值?它应该正确地将在ostream的编码中可表示的所有代码点转换为该编码,并且应该在代码点不可表示时报告错误.(例如,给定u'…'和UTF-8 ostream,应将三字节序列0xE2 0x80 0xA6写入流;但是给定u'â'和KOI8-R ostream,应报告错误.)

同样,如何在狭窄的ostream上打印非窄C字符串或字符串对象,转换为输出编码?

如果在ISO C++ 11中无法做到这一点,我将采用特定于平台的答案.

(灵感来自这个问题.)

The*_*Vee 3

正如您所指出的,没有operator<<(std::ostream&, const wchar_t)狭窄的 ostream。但是,如果您想使用该语法,您可以教ostream如何使用wchars,以便将该例程选为比首先需要转换为整数的例程更好的重载。

\n\n

如果您喜欢冒险:

\n\n
namespace std {\n  ostream& operator<< (ostream& os, wchar_t wc) {\n    if(unsigned(wc) < 256) // or another upper bound\n      return os << (unsigned char)wc;\n    else\n      throw your_favourite_exception; // or handle the error in some other way\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

否则,制作一个透明struct包含 awchar_t并具有自定义的简单字符friend operator<<,并在输出之前将宽字符转换为该字符。

\n\n

编辑:要与语言环境进行即时转换,您可以使用 中的函数<cwchar>,例如:

\n\n
ostream& operator<< (ostream& os, wchar_t wc) {\n    std::mbstate_t state{};\n    std::string mb(MB_CUR_MAX, \'\\0\');\n    size_t ret = std::wcrtomb(&mb[0], wc, &state);\n    if(ret == static_cast<std::size_t>(-1))\n        deal_with_the_error();\n    return os << mb;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

不要忘记将您的区域设置设置为系统默认值:

\n\n
std::locale::global(std::locale(""));\nstd::cout << L\'\xc5\xad\';\n
Run Code Online (Sandbox Code Playgroud)\n