2013-06-24 6 views
25

Возьмите этот пример кода:Порядок присвоения и порядок инициализации?

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, но наоборот.

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

ответ

23

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

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

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

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

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

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

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

выглядит

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

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

+0

+1 для тщательного ответа и искусства ascii, позволяет обойти вас до 2.5k rep –

15

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


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

+0

И даже для '&&' и '||' только встроенные версии имеют заданный порядок (именно поэтому вы никогда не должны перегружать их). –

+0

Для ',' тоже, если я правильно помню. –

2

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

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