Страницы

Поиск по вопросам

четверг, 12 декабря 2019 г.

странный синтаксис

#cpp #массивы #указатели #cpp11


очень неясно как работает данный код

int a[] = {4, 5, 2, 3, 1};
int i = *a;

for (;i;)
{
    std::cout << i--[a];  // не понятная строчка
}

//  output: 1325


к чему тут декремент применяется??? 

ну, очевидно, что к переменной i, раз цикл завершается.

Но как тогда происходят обращения к элементам массива ? почему нет ошибки компиляции ?

Впервый раз в жизни встречаю подобный код
    


Ответы

Ответ 1



Декремент тут применяется i хотя бы просто потому, что больше он в данной записи ни к чему применяться не может - справа от него стоит лексема [, которая началом выражения-операнда быть никак не может. Тема же эквивалентности a[i] и i[a] заезжена донельзя. Выражение x[y] по определению является лишь сокращенной формой записи для *(x + y). Один операнд должен быть массивом/указателем, а другой - целочисленным или enum значением. Причем ограничений на порядок указания операндов не накладывается. Поэтому ваше i--[a] эквивалентно *(i-- + a) эквивалентно *(a + i--) и эквивалентно a[i--]. Никакой "ошибки компиляции" тут нет. Вышесказанное относится именно и только к встроенному оператору []. Для перегруженного оператора [] порядок аргументов фиксирован, то есть для выражения x[y] будет рассматриваться только перегруженный вариант x.operator[](y), но не y.operator[](x).

Ответ 2



Оператор индексирования относится к классу постфиксных операторов. Он определяется следующим образом (стандарт C++, раздел 5.2.1 Subscripting) 1 A postfix expression followed by an expression in square brackets is a postfix expression. То есть за постфиксным выражением следует выражение в квадратных скобках. В этом выражении i--[a] i-- - это оператор пост-декремента, который относится к классу постфиксных выражений. Итак, имеется i-- [a] | | постфиксное выражение выражение в квадратных скобках Так что с точки зрения синтаксиса данное выражение совершенно корректное. Далее в той же самой цитате из стандарта имеется продолжение 1 ... One of the expressions shall have the type “array of T” or “pointer to T” and the other shall have unscoped enumeration or integral type. The result is of type “T.” The type “T” shall be a completely-defined object type.64 The expression E1[E2] is identical (by definition) to *((E1)+(E2)) из которого следует, что одно из выражений должно быть либо массивом, либо указателем, а другое выражение - перечислением или целочисленным типом. Какое из этих двух выражений какой должен иметь тип не существенно, так как по определению выражение E1[E2] эквивалентно выражению *((E1) + (E2)). В С++ вы можете написать даже более вычурную конструкцию, добавив знак плюс перед именем массива. Например, #include int main() { int a[] = { 0, 2, 4, 6, 8 }; int i = 0; std::cout << i++[+a] << std::endl; return 0; } В C такая конструкция i++[+a] не будет компилироваться, так как в C в отличии от C++ нельзя применять унарный плюс к имени массива. В C++ пользователь также может перегружать оператор индексирования для списка инициализации в фигурных скобках. Например, #include #include #include int main() { struct A { long long int operator []( std::initializer_list l ) const { return std::accumulate( l.begin(), l.end(), 0ll ); } }; std::cout << A()[{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }] << std::endl; return 0; } Вывод программы на консоль 55

Комментариев нет:

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