Самый неприятный parsing

Я видел код здесь, в Cpp Quiz [Вопрос # 38]

#include  struct Foo { Foo(int d) : x(d) {} int x; }; int main() { double x = 3.14; Foo f( int(x) ); std::cout << fx << std::endl; return 0; } 

Там сказано, что этот код плохо сформирован, потому что Foo f( int(x) ); будет рассматриваться как объявление функции, а не объявление объекта типа Foo . Насколько я знаю, это пример самого досадного parsingа. Мой вопрос в том, что такое синтаксис int (x) в выражении Foo f( int(x) ); означает? До сих пор я видел только объявления функций вроде:

  1. Foo f( int ); а также

  2. Foo f( int x );

То же, что и Foo f( int x ); ?

что такое синтаксис int(x) в выражении Foo f( int(x) ); означает?

Скобки вокруг x являются излишними и будут игнорироваться. Таким образом, int(x) совпадает с int x здесь, означает параметр с именем x с типом int .

То же, что и Foo f( int x ); ?

Да. Foo f( int(x) ); , является объявлением функции, которое называется f , возвращает Foo , принимает один параметр с именем x с типом int .

Вот объяснение со стандартом. $ 8.2 / 1 Разрешение неоднозначности [dcl.ambig.res] :

(акцент мой)

Неопределенность, возникающая из-за сходства между приведением в стиле функции и декларацией, упомянутой в [stmt.ambig], также может возникать в контексте декларации. В этом контексте выбор осуществляется между объявлением функции с избыточным набором круглых скобок вокруг имени параметра и объявлением объекта с использованием функции-стиля в качестве инициализатора. Так же, как и для двусмысленностей, упомянутых в [stmt.ambig], резолюция должна рассматривать любую конструкцию, которая может быть объявлением декларацией . [Примечание. Объявление может быть явно устранено путем добавления круглых скобок вокруг аргумента. Двусмысленности можно избежать, используя синтаксис инициализации копирования или синтаксиса списка или использование отличного от функционального стиля. – конец примечания] [Пример:

 struct S { S(int); }; void foo(double a) { S w(int(a)); // function declaration S x(int()); // function declaration S y((int(a))); // object declaration S y((int)a); // object declaration S z = int(a); // object declaration } 

– конец примера]

Таким образом, int(x) будет рассматриваться как объявление (параметра), а не как стиль функции.

Проблема состоит в том, что по неизвестным мне причинам действительным является включение имен параметров в скобки в прототипах. Так

 Foo f(int(x)); 

можно интерпретировать как

 Foo f(int x); 

который считается

 Foo f(int); 

Однако реальная проблема заключается в том, что авторы C ++, также по неизвестным мне причинам, решили, что было бы здорово иметь две разные формы синтаксиса для почти такой же семантики (инициализация экземпляра).

Это вводит неопределенность синтаксиса, которая «разрешена», говоря, что «если что-то может быть как объявлением, так и определением, то это объявление», вызывая ловушку.

Поэтому синтаксический анализатор C ++ должен иметь возможность анализировать произвольно большое количество токенов, прежде чем сможет решить, что является семантическим значением самого первого из них.

Это, видимо, не было бы слишком большой проблемой, кроме писателей компилятора, но, тем не менее, это значит, что и тот, кто читает код на C ++, должен понимать то же самое, и для нас это сложнее. От этого «самое неприятное».

Давайте будем гением компьютера.