Почему "Foo f (Bar()); может быть объявлением функции, которая принимает тип Bar и возвращает тип Foo?

Я встретил этот вопрос на С++:

Вопрос: Является ли следующее определение или декларация?

Foo f(Bar());

Ответ. Возможно, это либо объявление функции, которая принимает тип Bar, и возвращает тип Foo, либо это определение f как тип Foo, у которого есть конструктор, который принимает тип Bar. Проблема заключается в том, что синтаксис для обоих идентичен, поэтому для решения этой проблемы стандарт С++ утверждает, что компилятор должен предпочесть объявления функций для определения объектов, где он неспособен сделать различие.

- Я не понимаю, почему это может быть "объявление функции, которая принимает тип Bar и возвращает тип Foo"? как появилась скобка "()" в списке параметров?

Ответ 1

Функция f фактически принимает указатель на функцию, которая не принимает аргументов и дает Bar. Тип аргумента f - Bar (*)().

Этот код не скомпилируется (и мы можем видеть фактический тип аргумента в сообщении об ошибке):

class Foo { };
class Bar { };

Foo f(Bar());

int main() {
  Bar b;
  f(b);
  return 0;
}

Но этот код компилируется:

class Foo { };
class Bar { };

Foo f(Bar());

Bar g();

int main() {
  f(g);
  return 0;
}

Второе значение, которое может иметь, как вы говорите в вопросе, состоит в том, что вы создаете новый объект Foo с именем f, и вы вызываете конструктор с помощью Bar() (новый экземпляр Bar). Он будет похож на:

Foo f = Foo(Bar());

В этой ситуации Foo f(Bar());, хотя первая интерпретация выбирается компилятором.

Несколько смутно, если вы добавите еще один набор скобок, как в

Foo f((Bar()));

компилятор выбирает вторую интерпретацию.