Перегрузка оператора << с basic_ostream

Почему типичный заголовок потока управления с пользовательским классом 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 никогда не упоминается при разговоре о перегрузке потоковых операторов?

1 ответ

Решение

На практике используются два разных типа символов:

  1. Windows использует wchar_t в результате обещаний, сделанных людьми Unicode давным-давно (этот Unicode будет использовать только 16 битов, и что каждый символ будет состоять только из одной единицы), и которые были нарушены с тех пор.
  2. Все остальные используют 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).

Другие вопросы по тегам