Поведение вашего кода неуказано в соответствии со стандартом C ++.
Следующее (я удалил std::endl
для простоты)
std::cout << "Hello, world!" << print( std::cout );
эквивалентно этому:
std::operator(operator<<(std::cout, "Hello, World!"), print(std::cout));
, который является вызовом функции, передавая два аргумента:
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;
It будет печатать одинаковое значение для обоих. Например, этот пример в ideone печатает это:
0x804a044
0x804a044
Также обратите внимание, что я не использовал явное cast; скорее std::cout
- неявно преобразован в тип указателя.
Надеюсь, что это поможет.
Каков правильный способ записи функции, которая вставляет данные в ostream, но которая также может связываться с оператором & lt ; blockquote>
Когда это зависит от того, что вы подразумеваете под цепочкой? Очевидно, что следующее не будет работать (как описано выше):
std::cout << X << print(std::cout) << Y << Z; //unspecified behaviour!
Независимо от того, как вы пишете
print()
.Однако это четко определено:
print(std::cout) << X << Y << Z; //well-defined behaviour!
В вашем заявлении std::cout << "Hello, world!" << print( std::cout ) << std::endl
не определено, происходит ли std::cout << "Hello, world!"
до или после print( std::cout )
. Вот почему порядок может быть не таким, каким вы ожидаете.
Значение hex исходит из того факта, что вы также выполняете std::cout << std::cout
(print
возвращает std::cout
, который подается в <<
цепь). Правая рука std::cout
преобразуется в void *
и печатается на выходе.
Это сработает, чтобы объединить print
с <<
и управлять порядком:
print( std::cout << "Hello, world!" ) << std::endl;
Или, если вы хотите, чтобы функция, вызываемая с помощью <<
, см. ответ Йоахима.
Причина в том, что ваша функция print () будет вычисляться до остальной части инструкции и возвращать ссылку на cout, которая тогда фактически печатается как указатель (cout & lt; cout). Этот порядок оценки на самом деле является неуказанным поведением, но, похоже, имеет место с вашим компилятором.
Что касается определения функции «известно» потоком, которая фактически определила поведение с одинаковой функциональностью, это сработает; / g2]
#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;
}
См. также этот ответ для более подробной информации о том, что «неопределенный» на самом деле означает в этом случае.
До C ++ 11 класс std::ostream
имеет функцию преобразования в void*
. Поскольку ваша функция print
возвращает std::ostream&
, при оценке std::cout << print(...)
возвращаемое значение std::ostream
l неявно преобразуется в void*
, а затем выводится как значение указателя. Вот почему есть шестнадцатеричный вывод.
Поскольку C ++ 11, эта функция преобразования заменяется на явную функцию преобразования на bool
, поэтому попытка вывести std::ostream
.
До C ++ 17 перегруженный оператор считается вызовом функции для анализа порядка оценки и порядка оценки различных аргументов вызов функции не указан. Поэтому не странно, что сначала оценивается функция print
, из-за чего вывод How are you?
выводится первым.
Поскольку C ++ 17, порядок оценки операндов оператора <<
строго из слева направо, а операнды перегруженного оператора имеют тот же порядок оценки, что и у булитного входа (см. подробнее здесь ). Таким образом, ваша программа всегда будет получать результат (предполагается, что print
возвращает что-то, что может быть выведено)
Hello, world! How are you?
something returned by print