Порядок вычисления параметров функции С++
Я понимаю, что когда я вызываю такую функцию, как
a(b(),c());
тогда поведение этого может быть неопределенным в <= С++ 14 и неопределенным в> = С++ 17 в том смысле, что компилятору решать, следует ли сначала вычислять b
или c
.
Я хотел бы знать лучший способ навязать порядок оценки. Я буду компилировать как С++ 14.
То, что сразу приходит на ум, выглядит примерно так:
#include <iostream>
int count = 5;
auto increment(){
return count++;
}
template <typename A, typename B>
auto diff(A && a, B && b){
return a - b;
}
int main() {
auto && a = increment();
auto && b = increment();
auto c = diff(a,b);
}
Я нахожусь в неопределенном поведении земли? Или это, как предполагается, "заставить" порядок оценки?
Ответы
Ответ 1
Точка с запятой, которая разделяет операторы, налагает отношение "происходит раньше". auto && a = increment()
должен быть оценен первым. Это гарантировано. Возвращенный временный a
будет привязан к ссылке a
(и его время жизни увеличено) перед вторым вызовом increment
.
Там нет UB. Это способ форсировать порядок оценки.
Единственное, что нужно здесь, это то, что если increment
вернул саму ссылку, то вам нужно было бы беспокоиться о проблемах жизни. Но если бы не было проблем с продолжительностью жизни, скажем, если бы он возвращал ссылку на count
, все равно не было бы UB из навязанной оценки a
а затем b
.
Ответ 2
Вот еще один способ форсировать порядок оценки, используя std::initializer_list
, который имеет гарантированный порядок слева направо оценки:
#include <numeric> // for accumulate
#include <initializer_list>
template <class T>
auto diff(std::initializer_list<T> args)
{
return std::accumulate(args.begin(), args.end(), T(0), std::minus<>{});
}
const auto result = diff({increment(), increment()});
Это ограничивает вас объектами того же типа, и вам нужно ввести дополнительные фигурные скобки.