为什么`std :: basic_ifstream <char16_t>`在c ++ 11中不起作用?

时间:2016-12-24 17:57:17

标签: c++ c++11 unicode wchar-t char16-t

以下代码按预期工作。源代码,文件“file.txt”和“out.txt”都用utf8编码。但是,当我在wchar_t的第一行将char16_t更改为main()时,它无效。我用-std=c++11尝试了gcc5.4和clang8.0。我的目标是将wchar_t替换为char16_t,因为wchar_t在RAM中占用两倍的空间。我认为这两种类型在c ++ 11及更高版本的标准中同样得到了很好的支持。我在这里想念什么?

#include<iostream>
#include<fstream>
#include<locale>
#include<codecvt>
#include<string>

int main(){
  typedef wchar_t my_char;

  std::locale::global(std::locale("en_US.UTF-8"));

  std::ofstream out("file.txt");
  out << "123正则表达式abc" << std::endl;
  out.close();

  std::basic_ifstream<my_char> win("file.txt");
  std::basic_string<my_char> wstr;
  win >> wstr;
  win.close();

  std::ifstream in("file.txt");
  std::string str;
  in >> str;
  in.close();

  std::wstring_convert<std::codecvt_utf8<my_char>, my_char> my_char_conv;
  std::basic_string<my_char> conv = my_char_conv.from_bytes(str);

  std::cout << (wstr == conv ? "true" : "false") << std::endl;

  std::basic_ofstream<my_char> wout("out.txt");
  wout << wstr << std::endl << conv << std::endl;
  wout.close();

  return 0;
}

修改

修改后的代码不能用clang8.0编译。它使用gcc5.4进行编译,但在运行时崩溃,如@Brian所示。

1 个答案:

答案 0 :(得分:4)

各种流类需要一组定义才能运行。标准库仅需要charwchar_t的相关定义和对象,但不需要char16_tchar32_t。我需要完成以下操作才能使用std::basic_ifstream<cT>std::basic_ofstream<cT>

  1. std::char_traits<cT>指定字符类型的行为方式。我认为此模板专门用于char16_tchar32_t
  2. 使用过的std::locale需要包含std::num_put<cT>构面的实例来格式化数字类型。可以只实例化这个方面,并且可以创建包含它的新std::locale,但标准并不强制它存在于std::locale对象中。
  3. 使用过的std::locale需要包含构面std::num_get<cT>的实例以读取数字类型。同样,此facet可以实例化,但默认情况下不需要存在。
  4. facet std::numpunct<cT>需要专门化并放入使用过的std::locale来处理小数点,千位分隔符和文本布尔值。即使它没有真正使用,它也会从数字格式和解析函数中引用。 char16_tchar32_t没有现成的专业化。
  5. facet std::ctype<cT>需要专门化并放入使用的facet中,以支持字符类型的扩展,缩小和分类。 char16_tchar32_t没有现成的专业化。
    1. facet std::codecvt<cT, char, std::mbstate_t>需要专门化并放入使用的std::locale以在外部字节序列和内部“字符”序列之间进行转换。 char16_tchar32_t没有现成的专业化。
  6. 大多数方面都相当容易:他们只需转发简单的转换或查看表格。但是,std::codecvt方面往往相当棘手,特别是因为从标准C ++库的角度来看std::mbstate_t是一种不透明的类型。

    所有这一切都可以完成。自从我上次为角色类型进行概念验证实施以来,已经有一段时间了。我花了大约一天的工作时间。当然,当我开始实现locales和IOStreams库之前的工作时,我知道我需要做什么。添加合理数量的测试而不仅仅是简单的演示可能需要一个星期左右的时间(假设我可以专注于这项工作)。