Почему `std :: basic_ifstream & lt; char16_t & gt;` не работает в c ++ 11?

Следующий код работает как положено. Исходный код, файл «file.txt» и «out.txt» кодируются с помощью utf8. Но это не работает, когда я меняю wchar_t в char16_t на первой строке main(), Я пробовал и gcc5.4 и clang8.0 с -std=c++11, Моя цель — заменить wchar_t с char16_t, как wchar_t занимает в ОЗУ два места Я думал, что эти 2 типа одинаково хорошо поддерживаются в стандартах 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.

2

Решение

Различные классы потока нуждаются в наборе определений для работы. Стандартная библиотека требует соответствующих определений и объектов только для char а также wchar_t но не для char16_t или же char32_t, Вне моей головы необходимо следующее std::basic_ifstream<cT> или же std::basic_ofstream<cT>:

  1. std::char_traits<cT> указать, как ведет себя тип символа. я считать этот шаблон специализирован для char16_t а также char32_t,
  2. Используется std::locale должен содержать экземпляр std::num_put<cT> фасет для форматирования числовых типов. Этот аспект может быть просто создан и новый std::locale содержащий его может быть создан, но стандарт не требует, чтобы он присутствовал в std::locale объект.
  3. Используется std::locale должен содержать экземпляр аспекта std::num_get<cT> читать числовые типы. Опять же, этот аспект может быть создан, но не обязательно должен присутствовать по умолчанию.
  4. грань std::numpunct<cT> должен быть специализированным и помещенным в использованный std::locale иметь дело с десятичными точками, тысячами разделителей и текстовыми логическими значениями. Даже если он на самом деле не используется, на него будут ссылаться функции числового форматирования и синтаксического анализа. Там нет готовой специализации для char16_t или же char32_t,
  5. Грани std::ctype<cT> должен быть специализирован и помещен в используемый фасет для поддержки расширения, сужения и классификации типов символов. Там нет готовой специализации для char16_t или же char32_t,
    1. Грани std::codecvt<cT, char, std::mbstate_t> должен быть специализированным и помещенным в использованный std::locale преобразовывать между внешними байтовыми последовательностями и внутренними «символьными» последовательностями. Там нет готовой специализации для char16_t или же char32_t,

Большинство аспектов довольно просто выполнить: им просто нужно переслать простое преобразование или выполнить поиск по таблице. Тем не менее std::codecvt Фасет, как правило, довольно сложно, особенно потому, что std::mbstate_t является непрозрачным типом с точки зрения стандартной библиотеки C ++.

Все это можно сделать. Прошло много времени с тех пор, как я в последний раз доказывал реализацию концепции для символьного типа. Это заняло у меня около одного дня работы. Конечно, я знал, что мне нужно делать, когда приступил к работе, реализовав ранее библиотеку locales и IOStreams. Добавление разумного количества тестов, а не просто демонстрация, вероятно, заняло бы у меня неделю или около того (при условии, что я действительно смогу сосредоточиться на этой работе).

4

Другие решения

Других решений пока нет …