TGViewer
this->notes. this->notes. @thisnotes · 4.53K subscribers
Post #182 1.16K
#cpp

Сегодня тривиальный пост.

Как распарсится это выражение?

a+++++b;

Варианты:
- ((a++) ++) + b;
- a + (++(++b));
- (a++) + (++b);

Последнее можно отмести сразу, т.к. очень плохо обобщается на более сложные случаи (как вообще такое разбирать?). Давайте выберем из двух других.
В C++ разбор идёт примерно слева направо сверху вниз, причём в текущий токен парсер пытается набрать как можно больше символов (это называется maximum munch, т.е. такая жадная стратегия), потому тут конечно можно распарсить как a + ++++b, но можно добрать ещё один плюс, чтобы получился не бинарный оператор плюс, а постфиксный инкремент, потому верен первый вариант. Ну и тут же легко понять, почему это не скомпилируется: a++ это prvalue (значение оригинального идентификатора a изменяется, но возвращается копия), когда как инкремент/декремент требуют lvalue в качестве аргумента.

Обратите внимание, что если тут расставить пробелы, то всё будет работать как надо (потому что пробел заканчивает набор текущего токена).

По примерно тем же причинам до C++11 нельзя было писать что-то вроде

std::vector<std::vector<int>> v;

потому что >> в конце считывалось как operator>>, а не два закрывающихся шаблона -> приходилось ставить между ними пробел.

Я уже чуть-чуть писал про most vexing parse. Давайте посмотрим ещё чуть-чуть.

Когда вы пишете вот такое в глобальном неймспейсе:

Type func(OtherType);

вы сразу понимаете, что это объявление функции. Однако бывают более неочевидные (просто потому что вы имеете в виду другое) кейсы, когда компилятор так же воспринимает объявление:

class X {
public:
X() {}
X(Type obj) : obj(obj) {}
private:
Type obj();
};


Вполне можно думать, что раз приватное и мы инициализируем, то это поле, но это так же объявление функции с именем obj, из-за чего такой код не скомпилируется.

Или более дикие примеры:

struct X {};
struct Y {
Y(const X&) {}
void f() {}
};


int main() {
Y y(X());
y.f();
}


Код не скомпилируется на выражении y.f(), из-за того, как мы инициализируем объект y: на самом деле это тоже объявление функции y, возвращающей Y и принимающей X. По-хорошему конечно использовать фигурные скобки для инициализации: Y y{X()}, — а можно поставить ещё одну пару скобок вокруг X: Y y((X())).

Короч будьте внимательны и читайте ошибки компиляции.
  • 👍 3
  • 👏 2
  • 🤯 1
More from @thisnotes
  1. Sep 17, 2026#common Сидите вы себе спокойно, разрабатываете поиск каких-нибудь объектов. Может это тов…
  2. Sep 9, 2026#cpp #books Да, книга 2001ого года. Мы ровесники. И да, в ней в основном обсуждаются какие…
  3. Sep 2, 2026#perf Попробовал собрать в кучку (кажется, немного сумбурно всё же) мысли по двум моментам…
  4. Aug 31, 2026Давайте новый тег заведём: #perf Во-первых, надо понять, что я вообще понимаю под перфом,…
  5. Aug 27, 2026#common Мы часто делаем системы, которые обладают какими-то ограничениями. Ограничения наш…
  6. Aug 24, 2026#list 0. [talk] Achieving Peak Performance for Matrix Multiplication in C++. Aliaksei Sala…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →