Могут ли оптимизаторы C / C ++ решить лениво оценить значения, которые используются только при оценке короткого замыкания?

Мне нравится рефакторинг сложных условий, таких как это:

if (foo(blah) || (bar(param1, param2, param3) && !obj.longMethodName())) ...

в это:

bool foo_true = foo(blah);
bool bar_true = bar(param1, param2, param3);
bool long_true = obj.longMethodName();

if (foo_true || (bar_true && !long_true)) ...

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

Но: в исходном коде из-за короткого замыкания, bar будет оцениваться только если foo возвращается true, а также longMethodName только если bar возвращается true,

Предположим, что функции «чистые», методы constи компилятор может видеть тела функций всего. Разрешено ли оптимизаторам C ++ откладывать оценку моих промежуточных значений до тех пор, пока они не понадобятся?

1

Решение

Конечно. При условии, что компилятор может видеть достаточно, чтобы определить
тот foo, bar а также obj.longMethodName() не имеют
другое влияние на наблюдаемое поведение вашего кода.

Есть ли какие-либо компиляторы это другой вопрос. Я скорее сомневаюсь
Это; это потребовало бы особой логики, которой нет в
обычный список методов оптимизации, для чего-то, что
практически никто не делает. (Я подозреваю, что большинство программистов
найти оригинальную версию, правильно отформатированную, чтобы быть более
удобочитаемее, чем тот, с большим количеством дополнительных переменных.)

РЕДАКТИРОВАТЬ:

Интересно, стоит ли указывать, что компилятор разрешен
вызвать все три функции, даже если написано if:

if ( foo( blah ) || (bar( p1, p2, p3 ) && ! obj.lMN() ) )

(Хотя я не могу себе представить, что бы.) Стандарт делает
нет требований в отношении того, какие функции вызываются, когда;
это только требует, чтобы наблюдаемое поведение было таким же
значения и в том же порядке — никаких гарантий в отношении
время) «как будто» формальная семантика программы была соблюдена.
И единственное, что считается наблюдаемым поведением, это IO
(в некоторой форме) и доступ к изменчивым объектам.

4

Другие решения

Нет. Ваш компилятор не имеет права проводить оптимизацию, потому что он не может определить, имели ли вы в виду короткое замыкание или хотите ли вы иметь потенциальный побочный эффект оценки bar не важно что.

1

Нет. C ++ не имеет понятия чистого метода без побочных эффектов, поэтому на самом деле нет способа его оптимизировать.

0

Проблема здесь в том, что foo а также bar может быть реализован в другом модуле компиляции, и C ++ не имеет понятия чистоты функции. Это означает, что foo а также bar может иметь побочные эффекты (изменения в экране или глобальные переменные) и, следовательно, должен быть оценен, чтобы получить ожидаемое поведение.

Интересно, что с помощью GCC функции могут быть объявлены с помощью pure приписывать. Это говорит компилятору, что функция не имеет побочных эффектов. И потому можно назвать ленивым. Увидеть Вот Больше подробностей.

0

Я не уверен, что назначение будет считаться побочным эффектом уже. По меньшей мере, трудно определить, безопасно ли перемещать реальный вызов.

Но я хотел бы отметить, что в C ++ 11 можно добиться того, что OP выполняет с почти таким же синтаксисом, который OP использует в примерах, использующих std::bind.

Это просто foo_true, не будет определяться как

bool foo_true = foo(blah);

скорее

auto foo_true = std::bind(foo, blah),

if может быть затем проверен как if( foo_true() || bar_true() ),

Будь то чище или нет, это личное дело ИМО. Но я считаю, что он ведет себя так, как хотел, так и ожидал. Полный код:

#include <iostream>
#include <functional>

using namespace std;

bool foo(int blah){
cout << "blah: " << blah << '\n';
return blah;
}

bool bar(bool negate_me){
cout << "negate_me: " << negate_me << '\n';
return !negate_me;
}

int main() {
bool test = true;
int param = 42;
auto foo_true = std::bind(foo, test);
auto bar_true = std::bind(bar, param);

if (foo_true() || bar_true() ) cout << "TEST\n";
return 0;
}

Выход:

blah: 1
TEST

bar не звонил. + Изменить test в false и так будет.

0
По вопросам рекламы [email protected]