Подтвердить что ты не робот

Порядок присваивания против порядка инициализации

Возьмите этот пример кода:

int a = 10;
int b = 20;
int c = 30;

int & foo1() {
    qDebug() << "foo1" << endl;
    return a;
}

int & foo2() {
    qDebug() << "foo2" << endl;
    return b;
}

int & foo3() {
    qDebug() << "foo3" << endl;
    return c;
}

int main(void)
{
    foo1() = foo2() = foo3() = 7;
}

Поскольку назначение идет справа налево, я ожидал увидеть foo3 первым и foo1 последним, но это наоборот.

Определены ли правила для таких сценариев и как? Кроме того, различает ли компилятор между присваиванием и другими операторами и как это возможно, если вы используете оператор = в другом контексте, чем инициализация? Может быть, цепное присвоение трактуется иначе, чем другие цепочки?

4b9b3361

Ответ 1

Полное выражение

foo1() = foo2() = foo3() = 7

может быть абстрагировано с помощью следующего дерева:

     =
   /   \
foo1()   = 
       /   \
    foo2()   =
           /   \
        foo3()   7

Листья этого дерева могут быть оценены в любом порядке. Ваш компилятор свободен в выборе. Только для вызова оператора присваивания сначала должны быть оценены выражения, зависающие на них. В вашем случае листья оцениваются в порядке foo1(), foo2(), а затем foo3().

Правовая ассоциативность = видна только в форме дерева, но не в порядке оценки. Дерево для

std::cout << foo1() << foo2() << foo3()

выглядит как

                   << 
                 /    \
              <<      foo3()
            /    \
         <<      foo2()
       /    \
std::cout   foo1()

Опять функции foo могут быть оценены в любом порядке, но порядок оценок operator<<() определен корректно. Есть интересный пост о точках последовательности, который очень хорошо описывает темы.

Ответ 2

Ассоциативная ассоциативность (т.е. справа налево) не связана с порядком оценки. * Порядок оценки операндов неуточнен.


* За исключением нескольких случаев, а именно &&, || и ,.

Ответ 3

Порядок оценки подвыражений не совпадает с тем, как применяется их результат!

foo1() можно назвать ранним, только само присваивание не должно применяться до того, как будут выполнены другие.