Вопрос:

ostream chaining, порядок вывода

c++ iostream chaining

1938 просмотра

5 ответа

221 Репутация автора

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

#include <iostream>

std::ostream& print( std::ostream& os ) {
  os << " How are you?" << std::endl;
  return os;
}

int main() {
  std::cout << "Hello, world!" << print( std::cout ) << std::endl;
}

Результат этого кода:

 How are you?
Hello, world!0x601288

Однако, если я разделяю цепочку выражений на два утверждения, как это

int main() {
  std::cout << "Hello, world!";
  std::cout << print( std::cout ) << std::endl;
}

то я, по крайней мере, получаю правильный порядок в выходе, но все равно получаю шестнадцатеричное значение:

Hello, world! How are you?
0x600ec8

Я хотел бы понять, что здесь происходит. Имеет ли нормальная функция приоритет operator<<, и поэтому порядок вывода обращается вспять? Каким образом можно написать функцию, которая вставляет данные в систему, ostreamно с которой также можно связать operator<<?

Автор: LowTechGeek Источник Размещён: 19.01.2012 06:22

Ответы (5)


3 плюса

139848 Репутация автора

Причина в том, что ваша функция print () будет оцениваться до остальной части инструкции и возвращать ссылку на cout, которая тогда фактически печатается как указатель (cout << cout). Этот порядок оценки - это фактически неопределенное поведение, но, похоже, это относится к вашему компилятору.

Что касается определения «функции», осведомленной о потоке, которая фактически определила поведение с одинаковой функциональностью, это сработает;

#include <iostream>

template <class charT, class traits>
  std::basic_ostream<charT,traits>& print ( std::basic_ostream<charT,traits>& os )
{
        os << " How are you?" << std::endl;
        return os;
}

int main() {
  std::cout << "Hello, world!" << print << std::endl;
}

См. Также этот ответ для более подробной информации о том, что «неопределенный» на самом деле означает в этом случае.

Автор: Joachim Isaksson Размещён: 19.01.2012 06:30

5 плюса

247954 Репутация автора

Решение

Поведение вашего кода не указано в соответствии со стандартом C ++.

объяснение

Следующее (я удаляю std::endlдля простоты)

std::cout << "Hello, world!" << print( std::cout ); 

эквивалентно этому:

std::operator<<(std::operator<<(std::cout, "Hello, World!"), print(std::cout));

который является вызовом функции, передавая два аргумента:

  • Первый аргумент: std::operator<<(std::cout, "Hello, World!")
  • Второй аргумент: print(std::cout)

Теперь в стандарте не указывается порядок, в котором оцениваются аргументы. Он не указан . Но ваш компилятор, кажется, сначала оценивает второй аргумент, поэтому он печатает «Как дела?». сначала оценивая второй аргумент на значение типа, std::ostream&которое затем передается на вызов, показанный выше (это значение является std::coutсамим объектом ).

Почему шестнадцатеричный вывод?

Вы получаете шестнадцатеричный вывод, потому что второй аргумент оценивается std::cout, который печатается как шестнадцатеричное число, потому что std::coutнеявно преобразуется в значение указателя void*типа, поэтому он печатается как шестнадцатеричное число.

Попробуй это:

void const *pointer = std::cout; //implicitly converts into pointer type!
std::cout << std::cout << std::endl;
std::cout << pointer << std::endl;

Он напечатает то же значение для обоих. Например, этот пример в ideone печатает это:

0x804a044
0x804a044 

Также обратите внимание, что я не использовал явное выражение; а std::coutэто неявно преобразуется в тип указателя.

Надеюсь, это поможет.


Каким образом можно написать функцию, которая вставляет данные в систему, ostreamно с которой также можно связать operator<<?

Когда это зависит от того, что вы подразумеваете под цепью? Очевидно, что следующее не будет работать (как объяснялось выше):

std::cout << X << print(std::cout) << Y << Z; //unspecified behaviour!

Независимо от того, как вы пишете print().

Однако это четко определено:

print(std::cout) << X << Y << Z; //well-defined behaviour!
Автор: Nawaz Размещён: 19.01.2012 06:32

1 плюс

67613 Репутация автора

В вашем заявлении std::cout << "Hello, world!" << print( std::cout ) << std::endlне определено, std::cout << "Hello, world!"происходит ли это до или после print( std::cout ). Вот почему заказ может быть не тем, что вы ожидаете.

Шестнадцатеричное значение исходит из того факта, что вы тоже делаете std::cout << std::cout( printвозвращается, std::coutкоторый подается в <<цепочку). Правая рука std::coutпреобразуется в a void *и печатается на выходе.

Автор: bames53 Размещён: 19.01.2012 06:34

1 плюс

232386 Репутация автора

Это будет работать, совмещать printс <<и контролировать порядок:

print( std::cout << "Hello, world!" ) << std::endl;

Или, если вы хотите, чтобы функция была вызвана <<, см. Ответ Йоахима.

Автор: Ben Voigt Размещён: 19.01.2012 06:36

1 плюс

5620 Репутация автора

Шестнадцатеричный выход

Перед C ++ 11 класс std::ostreamимеет функцию преобразования void*. Так как ваша printфункция возвращается std::ostream&, при оценке std::cout << print(...)возвращаемое значение std::ostreamlvalue будет неявно преобразовано void*и затем будет выводиться как значение указателя. Вот почему есть шестнадцатеричный вывод.

Так как C ++ , 11, эта функция преобразования заменяется посредством явной функции преобразования к bool, таким образом пытаясь выводить std::ostreamобъект становится плохо сформирован.

Порядок оценки

Перед C ++ 17 перегруженный оператор считается вызовом функции для анализа порядка оценки, а порядок оценки различных аргументов вызова функции не указан. Поэтому не странно, что printфункция сначала оценивается, а причины How are you?выводятся во-первых.

Начиная с C ++ 17, порядок оценки операндов оператора <<строго слева направо, а операнды перегруженного оператора имеют тот же порядок оценки, что и порядковый номер булитного (см. Подробнее здесь ). Таким образом, ваша программа всегда будет получать результат (предполагается, printчто возвращает то, что может быть выведено)

Hello, world! How are you?
something returned by print

ПРЯМОЙ ПРИМЕР

Автор: xskxzr Размещён: 05.03.2018 12:14
Вопросы из категории :
32x32