Порядок оценки параметров функции: это UB, если мы передаем ссылку?

Это поведение undefined:

void feedMeValue(int x, int a) {
  cout << x << " " << a << endl;
}
int main() {
  int a = 2;
  int &ra = a;
  feedMeValue(ra = 3, a); // equivalent to: feedMeValue(a = 3, a) (see note bellow)
  return 0;
}

потому что в зависимости от того, какой параметр оценивается, мы могли бы называть (3, 2) или (3, 3).

Однако это:

void feedMeReference(int x, int const &ref) {
  cout << x << " " << ref << endl;
}

int main() {
  int a = 2;
  int &ra = a;
  feedMeReference(ra = 3, a); // equivalent to: feedMeReference(a = 3, a) (see note bellow)
  return 0;
}

всегда будет выводить 3 3, поскольку второй параметр является ссылкой, и все параметры были оценены до вызова функции, поэтому, даже если второй параметр оценивается до после ra = 3, функция получила ссылку на a который будет иметь значение 2 или 3 во время оценки, но всегда будет иметь значение 3 во время вызова функции.

Является ли второй пример UB? Важно знать, потому что компилятор может свободно что-либо делать, если обнаруживает поведение undefined, даже если я знаю, что он всегда даст те же результаты.


Примечание. Я оставлю feedMeReference(ra = 3, a) в качестве ссылки на ответы ra, но вы должны заметить, что проблема проще эквивалентна, если мы назовем feedMeReference(a = 3, a) (проще, потому что мы исключаем ra, который находится на пути нашей проблемы (второй параметр является ссылкой)).

Ответы

Ответ 1

Это интересный вопрос. В вашем первом случае undefined, потому что объект изменен, а также доступ без промежуточной точки последовательности (на языке из С++ 03 --- С++ 11 использовал другой язык, чтобы сказать, по существу, то же самое). Во втором случае поведение undefined отсутствует, потому что инициализация ссылки с lvalue не имеет доступа объект, поэтому единственный доступ - ra = 3. (Вызов функция устанавливает точку последовательности, поэтому доступ в функция имеет точку последовательности между ними и ra = 3.)