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

时间:2016-12-12 18:58:38

标签: c++ iostream widechar

如果您将wchar_tchar16_tchar32_t值提供给狭窄的ostream,它将打印代码点的数值。

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

打印x120120120。这是因为operator<<basic_ostream的特定组合有charT,但其他字符类型没有类似的运算符,因此它们会以静默方式转换为{{ 1}}并以这种方式打印。同样,非窄字符串文字(intL"x"u"x")将以静默方式转换为U"X"并打印为指针值,而非窄字符串对象void*wstringu16string)甚至无法编译。

所以,问题是:在狭窄的ostream上打印u32stringwchar_tchar16_t值的最不可思议的方法是什么,作为角色,而不是作为代码点的数值?它应该正确地将在ostream的编码中表示的所有代码点转换为该编码,并且当代码点不可表示时应报告错误。 (例如,给定char32_t和UTF-8 ostream,应将三字节序列0xE2 0x80 0xA6写入流;但是给定u'…'和KOI8-R ostream时,应该出现错误报道)。

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

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

(灵感来自this question。)

1 个答案:

答案 0 :(得分:2)

如你所知,狭窄的ostream没有operator<<(std::ostream&, const wchar_t)。如果你想使用语法,你可以教ostream如何处理wchar s,以便选择该例程作为一个更好的重载,需要先转换为整数。

如果你有冒险的感觉:

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

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

修改:要与语言环境进行实时转换,您可以使用<cwchar>中的功能,例如:

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

不要忘记将您的语言环境设置为系统默认值:

std::locale::global(std::locale(""));
std::cout << L'ŭ';