Неясный самый неприятный разбор

Предположим, что есть следующий класс Foo.

struct Foo
{
  int i;
};

если я хочу создать экземпляр этого класса и инициализировать его, я должен сделать: Foo foo1 = Foo(); для вызова конструктора.

int main(void)
{
    foo1 = Foo(); 
    cout << foo1.i << " : " << foo1.j << endl; // " 0 " 
}

затем я подумал, что вызову конструктор по умолчанию со следующей строкой, но это не так:

int main(void)
{
    Foo foo2(); // most vexing parse
    cout << foo2  << endl; // " 1 " ??? why?
    foo2.i++; // error: request for member ‘i’ in ‘foo2’, which is of non-class type ‘Foo()’ 
}

Почему foo2 инициализируется как int(1), а не как Foo()?

Я знаю про самый неприятный синтаксический анализ, он говорит о том, что, насколько я понимаю, когда строку можно интерпретировать как функцию, она интерпретируется как функция.

Но foo1() интерпретируется как int, а не как функция или класс Foo.

Строка Foo foo2() компилируется, потому что интерпретируется как прототип функции. ХОРОШО.

Почему эта строка компилируется? cout << foo2 << endl;

Выводит ли он адрес функции foo2?


person Guillaume D    schedule 22.07.2019    source источник
comment
Используйте отладчик, чтобы узнать, какую operator<< перегрузку выбрал компилятор.   -  person Ulrich Eckhardt    schedule 22.07.2019
comment
если я хочу создать экземпляр этого класса и инициализировать его, я должен сделать: Foo foo1 = Foo(); для вызова конструктора. Нет, вы должны просто сделать Foo foo1; или Foo foo1 {};, в зависимости от того, что вы хотите сделать.   -  person ruohola    schedule 22.07.2019
comment
Обратите внимание, что здесь нет самого неприятного синтаксического анализа. Самый неприятный синтаксический анализ включает в себя то же самое правило для объявлений функций. Вот пример самого надоедливого разбора: Foo foo2(int()); (переписал свой комментарий, так как исходный пример был не совсем полным)   -  person eerorika    schedule 22.07.2019


Ответы (1)


Как вы сказали, Foo foo2(); - это объявление функции. Для cout << foo2 foo2 будет распадаться на указатель функции, а затем неявно преобразуется в bool. В качестве ненулевого указателя на функцию преобразованный результат равен true.

Без использования boolalpha std::basic_ostream<CharT,Traits>::operator<< будет вывод 1 для true.

Если boolalpha == 0, то преобразует v в тип int и выполняет целочисленный вывод.

Вы можете увидеть это более четко, используя std::boolalpha.

cout << boolalpha << foo2  << endl;  // print out "true"
person songyuanyao    schedule 22.07.2019