Вопрос

Хорошо известно, что пользователь может определить манипуляторы потока, как это:

ostream& tab(ostream & output)
{
    return output<< '\t';
} 

И это можно использовать в основной() так:

cout<<'a'<<tab<<'b'<<'c'<<endl;

Пожалуйста, объясните мне, как это работает? Если Оператор < предполагает в качестве второго параметра указатель на функцию, которая берет и возвращает ostream &, Тогда, пожалуйста, объясните, почему нужно? Что было бы неправ, если функция не берет и возвращает ostream & но это было пустота вместо ostream &?

Также интересно, почему «декабря», «шестнадцатеричные» манипуляторы вступают в силу, пока не изменяем между ними, а пользовательские манипуляторы должны всегда использоваться для того, чтобы вступить в силу для каждой потоковой передачи?

Это было полезно?

Решение

Стандарт определяет следующее operator<< Перегрузка в basic_ostream Шаблон класса:

basic_ostream<charT,traits>& operator<<(
    basic_ostream<charT,traits>& (*pf) (basic_ostream<charT,traits>&) );

Эффекты: нет. Не ведет себя как функцию отформатированной вывода (как описано в 27.6.2.5.1).

Возвращает: pf(*this).

Параметр является указателем на функцию, принимающую и возврату ссылки на std::ostream.

Это означает, что вы можете «поток» функцию с этой подписью к ostream Объект, и это влияет на вызов этой функции на поток. Если вы используете имя функции в выражении, то он (обычно) преобразуется в указатель на эту функцию.

std::hex является std::ios_base Манипулятор определяется следующим образом.

   ios_base& hex(ios_base& str);

Эффекты: Звонки str.setf(ios_base::hex, ios_base::basefield).

Возвращает: ул.

Это означает, что потоковое hex чтобы ostream Установит флаги вывода базового форматирования для вывода номеров в шестнадцатеричном порядке. Манипулятор не выводит ничего самого.

Другие советы

В этом нет ничего плохого, кроме того, что нет перегруженного << Оператор, определенный для него. Существующие перегрузки для << ожидают манипулятора с подписью Ostream & (* FP) (Ostream &).

Если вы дали ему манипулятор с типом Ostream & (* FP) () Вы получите сообщение об ошибке компилятора, так как не иметь определение для Оператор << (Ostream &, Ostream & (* FP) ()). Отказ Если вы хотите эту функциональность, вам придется перегружать оператор << для принятия манипуляторов этого типа.

Вам придется написать определение для этого:
OREAM & OSTREAM :: Оператор << (Orstream & (* m) ())

Имейте в виду здесь, что здесь ничего магического не происходит. Библиотеки потока сильно полагаются на стандартный Особенности C ++: перегрузка оператора, классы и ссылки.

Теперь, когда вы знаете, как вы можете создать функциональность, которые вы описали, вот почему мы не делаем:

Не передавая ссылку на поток, мы пытаемся манипулировать, мы не можем внести модификации потока, подключенного к конечному устройству (CIN, OUT, ERR, FSTREAM и т. Д.). Функция (MODITIFIER'S все просто функционирует с модными именами). Подключитесь с остальным всем к правой части модификатора, не сделает его до окончательного устройства, но скорее будет отправлено на любой острую функцию / модификатор.

Думать о потоках, как это

cout << "something here" << tab << "something else"<< endl;

действительно значит

(((cout << "something here") << tab ) << "something else" ) << endl);

Там, где каждый набор скобок делает что-то для Cout (запись, модифицировать и т. Д.), а затем возвращает Cout, чтобы на нем можно работать следующий набор скобок.

Если ваша вкладка модификатор / функция не предпринимала ссылку на Ostream, это придется каким-то догадаться, что остром оставил от << оператора для выполнения своей задачи. Вы работали с Cour, Cerr, какой-то файловый поток ...? Интернеты функции никогда не узнают, если они не передают эту информацию какой-то как, и почему бы не то, как настолько простую, как ссылка на него.

Теперь, чтобы действительно водить точку домой, давайте посмотрим на что endl На самом деле есть и какая перегруженная версия оператора << мы используем:

Этот оператор выглядит так:

  ostream& ostream::operator<<(ostream& (*m)(ostream&)) 
  {  
      return (*m)(*this);
  }

endl выглядит так:

  ostream& endl(ostream& os)      
  {  
      os << '\n'; 
      os.flush();     
      return os;
  }

Целью ENDL является добавление новой строки и промывки потока, убедившись, что все содержимое внутреннего буфера потока были записаны на устройство. Чтобы сделать это, сначала нужно написать « N» к этому потоку. Затем он должен сказать поток, чтобы промыть. Единственный способ ENDL, чтобы узнать, какой поток для записи и вспомогательного, предназначен для оператора, чтобы передать эту информацию в функцию ENDL, когда она его вызывает. Это было бы похоже, что я говорю вам вымыть мою машину, но никогда не говорите, какая машина моя на полной парковке. Вы никогда не сможете сделать вашу работу. Тебе нужна, чтобы избрать тебя, моя машина, или я могу мыть его сам.

Я надеюсь, что это проясняет вещи

PS - если вы случитесь случайно найти мою машину, пожалуйста, мыть ее.

Как правило, манипулятор потока устанавливает некоторые флаги (или другие настройки) на объекте потока, так что в следующий раз он используется, он будет действовать в соответствии с флагами. Следовательно, манипулятор возвращает тот же объект, который прошел. То operator<< Перегрузка, которая называемыми «Manipulator» уже имеет этот объект, конечно, так как вы заметили, возвращаемое значение не требуется для этого случая. Я думаю, что это охватывает все стандартные манипуляторы - все они возвращают свой вклад.

Тем не менее, с возвращаемой стоимостью структура достаточно гибкой, чтобы таможенный манипулятор потока мог Верните другой объект, предположительно обертку для объекта его данного. Этот другой объект будет возвращен из cout << 'a' << tab, и мог сделать то, что встроенный ostream Параметры форматирования не поддерживают.

Не уверен, как вы устроили этот другой объект, чтобы освободиться, поэтому я не знаю, насколько это практично. Возможно, это должно быть что-то своеобразное, как прокси-объект, который управляется ostream сам. Тогда манипулятор будет работать только для пользовательских рубричных классов, которые активно поддерживают его, что обычно не является точкой манипуляторов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top