Привет. У меня просто каша в голове на эту тему. Из справочника:
All file I/O operations performed through std::basic_fstream<CharT> use the std::codecvt<CharT, char, std::mbstate_t> facet of the locale imbued in the stream.
std::codecvt<char, char, std::mbstate_t> identity conversion
std::codecvt<char16_t, char8_t, std::mbstate_t> conversion between UTF-16 and UTF-8 (since C++20)
std::codecvt<char32_t, char8_t, std::mbstate_t> conversion between UTF-32 and UTF-8 (since C++20)
std::codecvt<wchar_t, char, std::mbstate_t> conversion between the system's native wide and the single-byte narrow character sets
Из прочитанного создаётся ощущение, что все специализации fstream (кроме wchar_t и char) должны конвертировать в utf-8, а wchar_t в narrow char.
Что показывает практика: C utf-32 вроде так и происходит - на выходе в файле utf-8. А вот поведение wchar_t вообще не сходится с документацией. Он конвертирует не в narrow char, а в кодировку локали:
basic_ofstream<wchar_t> f("22");
locale l(f.getloc(), new std::codecvt_byname<wchar_t, char, mbstate_t>("ru_RU.CP1251"));
f.imbue(l);
f << L"й";
на выходе кс1251. Если локаль не указывать, то записи вообще нет. Пусть так, может даже удобно, но я вообще не увидел описание такого поведения в доках. Может это гцц специфично и вообще нестандартно? И кросплатформенно использовать wfstream для перекодировок не стоит. Ещё интересно можно ли во время выполнения узнать доступные локали (стд способами)? я не нашёл.