[gcc] разбор выражения

doublemother

Написал такой интересный код:
#include <iostream>
class podergach {
public:
podergach& operator ++ (int a) {
std::cout << "Подергали++" << std::endl;
}
podergach& operator ++ {
std::cout << "++Подергали" << std::endl;
}
podergach& operator + (podergach&) {
std::cout << "Сложили" << std::endl;
}
podergach& operator += (podergach&) {
std::cout << "Подопихали" << std::endl;
}
};

int main(int argc, char **argv) {
podergach A;
A += ++A+++++A;
return 0;
}

Скомпилил, запускаю, получаю вывод:
Подергали++
Подергали++
++Подергали
Сложили
Подопихали

Если расставить пробелы:
        A += ++A++ + ++A;

Получаю:
++Подергали
Подергали++
++Подергали
Сложили
Подопихали

Отсюда два вопроса:
1) Разве разбор выражения идёт не справа? Почему ++A+++++A разбирается на два постфиксных оператора (A++)++, а не два префиксных ++(++A) ?
2) С какого перепугу постфиксный оператор в первом примере выполняется раньше, чем префиксный? Где я что не понимаю?
З.ы. Про стандарт и undefined behaviour знаю.

Serab

постфиксный оператор в первом примере выполняется раньше, чем префиксный
отвечу на это, что пришло в голову.
Ты знаешь как желательно писать постфиксный ++/-- ?
именно: надо самому заботиться о сохранении промежуточного значения. Т.е. надо самому сделать какой-нибудь адекватный клон экземпляра, его вернуть, а внутренность при этом увеличить, и про то, когда он вызовется, ничего особенного нигде и не говорится.

doublemother

про то, когда он вызовется, ничего особенного нигде и не говорится.
как-то это хентайно...

yolki

Тут больше лексер виноват. По стандарту, лексер разбирает то, что у него собирается. вне зависимости от синтаксиса/семантики. типичный случай:

vector <vector <int>> M;

У компилятора с файлом общается лексер, который ничего про синтаксис/семантику не знает. он встречает >> и разбирает его как правый сдвиг и имеет на это полное право (по стандарту!). Другое дело, что некоторые компиляторы это обходят и пишут здесь конкретный варнинг. по-хорошему в этой ситуации надо руками самому направлять лексический анализатор:

vector <vector <int> > M;

В твоей ситуации он будет делать именно так: собирается ++? => отдаём ++.
Есть ещё забавная штука, как порядок вычисления аргументов.
например в такой ситуации:

A+= (++A) + (--A);

не известно, кто раньше сработает - ++ или —. компилятор сделать так, что вычисляться эти значения будут и так и сяк.
да что там... даже вот тут:

somefunc(P(AP(BP(C;

не известно, который из P(.) вызовется раньше.

klyv

2) С какого перепугу постфиксный оператор в первом примере выполняется раньше, чем префиксный? Где я что не понимаю?
может, потому что _все_ постфиксные операторы имеют больший приоритет?

Andbar

<гнусный оффтопик>
C:\temp>"S:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat"&cl /EHsc "2.cpp"
Setting environment for using Microsoft Visual Studio 2008 x86 tools.
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

2.cpp
c:\temp\2.cpp(6) : error C4716: 'podergach::operator++' : must return a value
c:\temp\2.cpp(9) : error C4716: 'podergach::operator++' : must return a value
c:\temp\2.cpp(12) : error C4716: 'podergach::operator+' : must return a value
c:\temp\2.cpp(15) : error C4716: 'podergach::operator+=' : must return a value
:smirk: </гнусный оффтопик>

doublemother

Это детали, это я знаю. gcc такое позволяет, поэтому я в данный момент не заморачивался.
А так сам не раз ругался на интересные функции в чужом коде вида:
bool myfunc (params) {
if (smth) return true;
}

doublemother

Забавно. Про последний пример читал, а вот про операторы думал, что там всё-таки более строго.

bleyman

Нет же, Базилио правильно пишет, лексер про приоритет ничего не знает, поэтому жадно делает из символов самые длинные лексемы. То есть последовательность +++++ всегда побьётся на ++, ++, +, а уже потом синтаксический анализатор будет пытаться расставить скобке.
Оставить комментарий
Имя или ник:
Комментарий: