Ответ 1
Одна неприятная вещь о операторах перенаправления <<
заключается в том, что они интуитивно передают индею "последовательного вычисления", которой действительно нет.
Когда вы пишете
std::cout << f() << g() << std::endl;
вывод покажет результат f()
, а затем результат g()
, но фактический вызов g()
может произойти до вызова f()
.
Это даже хуже, чем это... это не то, что последовательность не предсказуема, но это действительно само понятие последовательности недействительно. В
std::cout << f(g()) << h(i()) << std::endl;
это, например, законно, что первая вызываемая функция - это g()
, за которой следует i()
, затем h()
и, наконец, f()
. Он даже не гарантировал, что порядок будет одинаковым для всех вызовов (не потому, что разработчикам компиляторов нравится высмеивать вас, а потому, что код может быть встроен, и компилятор может решить другой порядок, если содержащая функция встроена в другом контексте).
Единственными операторами С++, которые гарантируют последовательность в порядке оценки, являются:
-
&&
: сначала оценивает левую сторону и только если результат "истина" оценивает правую сторону. -
||
: сначала оценивает левую сторону, и только если результат "false" оценивает правую сторону. -
?:
: сначала оценивает условие, а затем только второй или третий операнд -
,
: оператор запятой... оценивает левую сторону, отбрасывает значение и затем оценивает и возвращает правую сторону. ПРИМЕЧАНИЕ: запятые между функциональными параметрами НЕ являются операциями запятой и не налагается порядок оценки.
Кроме того, этот guaratee действителен только для предопределенных операторов. Если вы перегружаете &&
, ||
или ,
в своем классе, они просто нормальные операторы без каких-либо специальных ограничений на порядок оценки.
Любой другой оператор не накладывает никаких ограничений на порядок оценки, и это включает в себя <<
, даже если использование трюков в использовании этого.