Ответ 1
Оператор sizeof() вычисляется во время компиляции. Выражения НЕ. Это тип выражения, которое вычисляется (во время компиляции), а затем используется sizeof().
Итак, в первом:
sizeof( x += 1);
Тип x - int. Результатом оператора + = остается int. Поэтому sizeof() по-прежнему является размером int.
В этом:
sizeof(arr+0);
Здесь arr - массив и вернет размер массива (если он используется сам по себе). Но оператор + приводит к распаду массива в указатель. Результатом оператора + для массива и целого является указатель. Таким образом, оператор sizeof() вернет размер указателя.
(п. 5.3.3/4) Стандартные преобразования lvalue-to-rvalue (4.1), array-to-pointer (4.2) и стандартные для-указателя (4.3) не применяются к операнду sizeof.
Это означает, что:
std::cout << sizeof(arr);
// would print sizeof(int)* 5 (because there is no conversion)
// if sizeof() had behaved like a normal function there
// would have been a conversion but as you pointed out that
// does not apply.
Но здесь:
std::cout << sizeof(arr + 5);
// prints the sizeof(int*) because the result of the expression
// is a pointer type (int*)
В качестве примечания:
Вот почему
int x[0];
int const xSize = sizeof(x)/sizeof(x[0]);
// This works correctly even though x[0] is technically
// not valid if used in a real expression (but is valid here).