Почему типичный заголовок потока управления с пользовательским классом C
как правило, так:
std::ostream& operator<<(std::ostream& os, const C& c);
std::istream& operator>>(std::istream& is, C&);
и не так
template <class CharT, class Traits>
std::basic_ostream<CharT, Traits>& operator<<(
std::basic_ostream<CharT, Traits>& os
const C& c);
template <class CharT, class Traits>
std::basic_istream<CharT, Traits>& operator>>(
std::basic_istream<CharT, Traits>& is
C& c);
У меня вопрос, почему обычная перегрузка потоковых операторов выполняется с std::ostream
, который является typedef для char
из std::basic_ostream
и почему это не сделано напрямую с std::basic_ostream
?
Например:
class C
{
...
};
std::ostream& operator<<(std::ostream& os, const C& c)
{
...
}
int main()
{
C c;
std::wofstream myFile("myFile.txt");
myFile << c; //Impossible
}
operator<<
здесь написано ограничить нас использовать только потоковый объект, который специализирован для char
(std::ostream
, std::ostringstream
…)
Так что если использовать std::ostream
более ограничивающий, чем std::basic_ostream
,
Зачем std::basic_ostream
никогда не упоминается при разговоре о перегрузке потоковых операторов?
На практике используются два разных типа символов:
wchar_t
в результате обещаний, сделанных людьми Unicode давным-давно (этот Unicode будет использовать только 16 битов, и что каждый символ будет состоять только из одной единицы), и которые были нарушены с тех пор.char
который теперь в основном считается байтом в кодировке UTF-8 (очевидно, не универсально).Оглядываясь назад, введение wchar_t
(и тем более char16_t
а также char32_t
) был опрометчив, и мир был бы лучше, если бы char
будет использоваться. В результате, те, кого не беспокоит Windows, не заботятся о wchar_t
версия операций ввода-вывода и Windows в целом, похоже, используют IOStreams в целом (реализация MSVC ++, как известно, медленная и нет никаких намерений что-либо с этим делать).
Другая причина заключается в том, что написание шаблонных операторов ввода-вывода усложняет и без того сложную систему. Мало кто, кажется, понимает IOStreams, и среди этих немногих еще меньше людей заинтересованы в поддержке нескольких типов символов.
Одним из аспектов воспринимаемой сложности с шаблонными операторами ввода-вывода является предположение о том, что реализация должна идти в заголовок, что, конечно, неверно, учитывая, что в сущности есть только два символьных типа, для которых создаются IOStreams (char
а также wchar_t
): хотя IOStreams Можно быть реализованным с другими типами символов, я уверен, что вряд ли кто-то на самом деле делает это. Хотя я знаю, что для этого нужно, мне, вероятно, понадобится хотя бы день, чтобы определить все необходимые аспекты. Таким образом, определения шаблона мог быть определены в подходящих единицах перевода и созданы там. В качестве альтернативы, вместо определения операторов являются шаблонами, они могут быть полностью специализированными.
Независимо от того, как определены шаблонные операторы, обычно это больше работы. Если сделано наивно (то есть непосредственно с помощью, например, std::ctype<cT>
) результат будет медленным и при правильном выполнении (т. е. кэширование результатов из std::ctype<cT>
) это будет довольно сложно.
Взять все вместе: зачем?
Если бы мне пришлось написать std::wostream
или читать из std::wistream
Я бы на самом деле создал буфер потока фильтрации, который просто переводил бы написанные / прочитанные символы, используя подходящий std::codecvt<...>
аспект (или даже просто используя std::ctype<wchar_t>
«s widen()
или же narrow()
). Это не будет иметь дело с надлежащей интернационализацией строк, но std::locale
в любом случае объекты не совсем соответствуют надлежащей интернационализации (вам нужно что-то вроде ICU для этого).
Других решений пока нет …