Порядок оценки перегруженного оператора | - PullRequest
2 голосов
/ 25 августа 2011

5.15 Логический оператор ИЛИ в стандарте говорит следующее:

В отличие от |, || гарантирует оценку слева направо;

Означает ли это, что где-то, что я не могу найти в стандарте, | определено для оценки справа налево или что оно определяется реализацией? Это меняется, когда оператор перегружен? Я написал быструю программу для проверки этого, и MSVC ++ и GCC, кажется, оценивают справа налево .

#include<iostream>
using namespace std;

int foo = 7;

class Bar {
public:
    Bar& operator|(Bar& other) {
        return *this;
    }
    Bar& operator++() {
        foo += 2;
        return *this;
    }
    Bar& operator--() {
        foo *= 2;
        return *this;
    }
};

int main(int argc, char** argv) {
    Bar a;
    Bar b;
    Bar c = ++a | --b;
    cout << foo;
}

Это выводит 16. Если ++a и --b переключены, то выдается 19.

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

Ответы [ 3 ]

4 голосов
/ 25 августа 2011

Пока игнорируйте этот оператор и просто примите к сведению:

(x + y) * (z + 1)

Здесь оба операнда должны быть оценены до того, как умножение может произойти (иначе мы не знали бы, что умножать).В C ++ порядок, в котором это делается, неопределен : сначала он может быть (x + y) или сначала (z + 1), что бы компилятор ни чувствовал лучше. †

То же самоеверно для оператора |.Однако оператор || должен замкнуть накоротко , и для этого он должен оценить строго слева направо.(И если левая оценка дает true, оценка заканчивается без оценки правого операнда.) Вот что означает это предложение.

† Обратите внимание, что оно может не иметь предпочтения тем или иным способом, и просто оцените впорядок в списке.Вот почему вы получаете результат, который вы делаете, хотя вы не можете полагаться на него на уровне языка.

2 голосов
/ 25 августа 2011

Как говорили другие, это означает, что порядок оценки обеих сторон не определен.Чтобы ответить на ваши другие вопросы -

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

Нет,ваш случай не изменяет foo между двумя соседними точками последовательности.Перед входом в функцию и перед выходом из нее всегда существует точка последовательности, что означает, что обе модификации foo происходят между двумя различными парами точек последовательности.

Отличается ли это, когда оператор перегружен?

Во всем разделе 5 говорится только о встроенных операторах.Для пользовательских реализаций операторов правила не применяются.Так же и для ||, для определенных пользователем операторов порядок не указан.Но обратите внимание, что это только для определенных пользователем операторов;не когда оба операнда преобразуются в bool и запускают встроенный оператор:

struct A { 
  operator bool() const { return false; }
};

struct B {
  operator bool() const { return true; }
};

int main() {
  A a;
  B b;
  a || b;

  shared_ptr<myclass> p = ...;
  if(p && p->dosomething()) ...;
}

Сначала всегда выполняется A::operator bool, а затем B::operator bool.И он будет вызывать p->dosomething(), только если p оценивается как true.

2 голосов
/ 25 августа 2011

Означает ли это, что я не могу найти в стандарте, |определяется для оценки справа налево, или что это определяется реализацией?

Педагогически порядок вычисления аргументов оператора | не указан.Таким образом, это означает, что операнды могут оцениваться в любом порядке.

Однако порядок вычисления операндов логических операторов (т. Е. &&, || и т. Д.) И оператора запятой указывается, т. Е. Слева направо.

...