为什么 `std::basic_ifstream<char16_t>` 在 C++11 中不起作用?
Why does `std::basic_ifstream<char16_t>` not work in c++11?
以下代码按预期工作。源代码,文件"file.txt"和"out.txt"都是用utf8编码的。但是当我在 main()
的第一行将 wchar_t
更改为 char16_t
时,它不起作用。我已经用 -std=c++11
尝试了 gcc5.4 和 clang8.0。我的目标是用 char16_t
替换 wchar_t
,因为 wchar_t
在 RAM 中占用两倍 space。我认为这两种类型在 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 所示。
各种流 类 需要一组定义才能运行。标准库只需要 char
和 wchar_t
的相关定义和对象,而不需要 char16_t
或 char32_t
。在我的脑海中,需要以下内容才能使用 std::basic_ifstream<cT>
或 std::basic_ofstream<cT>
:
std::char_traits<cT>
指定字符类型的行为方式。我认为这个模板专门用于char16_t
和char32_t
。
- 使用的
std::locale
需要包含 std::num_put<cT>
facet 的实例来格式化数字类型。这个方面可以被实例化,并且可以创建一个包含它的新 std::locale
,但标准并不强制要求它存在于 std::locale
对象中。
- 使用的
std::locale
需要包含面 std::num_get<cT>
的实例才能读取数字类型。同样,这个方面可以实例化,但默认情况下不需要存在。
- 方面
std::numpunct<cT>
需要专门化并放入使用的 std::locale
中以处理小数点、千位分隔符和文本布尔值。即使它没有真正被使用,它也会被数字格式化和解析函数引用。 char16_t
或 char32_t
没有现成的专业化。
- facet
std::ctype<cT>
需要专门化,放到used facet中,支持字符类型的加宽、缩窄和分类。 char16_t
或 char32_t
没有现成的专业化。
- 方面
std::codecvt<cT, char, std::mbstate_t>
需要专门化并放入使用的 std::locale
以在外部字节序列和内部 "character" 序列之间进行转换。 char16_t
或 char32_t
没有现成的专业化。
大多数方面都相当容易做到:它们只需要转发一个简单的转换或进行 table 查找。然而,std::codecvt
方面往往相当棘手,特别是因为从标准 C++ 库的角度来看,std::mbstate_t
是一种不透明类型。
所有这些都可以做到。自从我上次为字符类型进行概念验证以来已经有一段时间了。我花了大约一天的工作时间。当然,在我着手工作之前已经实现了 locales 和 IOStreams 库时,我就知道我需要做什么。添加合理数量的测试而不是仅仅有一个简单的演示可能需要我一周左右的时间(假设我真的可以专注于这项工作)。
以下代码按预期工作。源代码,文件"file.txt"和"out.txt"都是用utf8编码的。但是当我在 main()
的第一行将 wchar_t
更改为 char16_t
时,它不起作用。我已经用 -std=c++11
尝试了 gcc5.4 和 clang8.0。我的目标是用 char16_t
替换 wchar_t
,因为 wchar_t
在 RAM 中占用两倍 space。我认为这两种类型在 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 所示。
各种流 类 需要一组定义才能运行。标准库只需要 char
和 wchar_t
的相关定义和对象,而不需要 char16_t
或 char32_t
。在我的脑海中,需要以下内容才能使用 std::basic_ifstream<cT>
或 std::basic_ofstream<cT>
:
std::char_traits<cT>
指定字符类型的行为方式。我认为这个模板专门用于char16_t
和char32_t
。- 使用的
std::locale
需要包含std::num_put<cT>
facet 的实例来格式化数字类型。这个方面可以被实例化,并且可以创建一个包含它的新std::locale
,但标准并不强制要求它存在于std::locale
对象中。 - 使用的
std::locale
需要包含面std::num_get<cT>
的实例才能读取数字类型。同样,这个方面可以实例化,但默认情况下不需要存在。 - 方面
std::numpunct<cT>
需要专门化并放入使用的std::locale
中以处理小数点、千位分隔符和文本布尔值。即使它没有真正被使用,它也会被数字格式化和解析函数引用。char16_t
或char32_t
没有现成的专业化。 - facet
std::ctype<cT>
需要专门化,放到used facet中,支持字符类型的加宽、缩窄和分类。char16_t
或char32_t
没有现成的专业化。- 方面
std::codecvt<cT, char, std::mbstate_t>
需要专门化并放入使用的std::locale
以在外部字节序列和内部 "character" 序列之间进行转换。char16_t
或char32_t
没有现成的专业化。
- 方面
大多数方面都相当容易做到:它们只需要转发一个简单的转换或进行 table 查找。然而,std::codecvt
方面往往相当棘手,特别是因为从标准 C++ 库的角度来看,std::mbstate_t
是一种不透明类型。
所有这些都可以做到。自从我上次为字符类型进行概念验证以来已经有一段时间了。我花了大约一天的工作时间。当然,在我着手工作之前已经实现了 locales 和 IOStreams 库时,我就知道我需要做什么。添加合理数量的测试而不是仅仅有一个简单的演示可能需要我一周左右的时间(假设我真的可以专注于这项工作)。