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

Есть ли некоротко замкнутый логический "и" в С++?

tl; dr: существует ли не короткое замыкание логическое И в С++ (похожее на &)?

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

IE:

bool Func1(int x, int y){
  if( x > y){
    cout << "ERROR- X > Y" << endl;
  }
}
bool Func2(int z, int q){
  if( q * 3 < z){
    cout << "ERROR- Q < Z/3" << endl;
  }
}
bool Func3(int x, int y, int z, int q){
  return ( Func1(x, y) && Func2(z, q) );
}

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


Резюме ответов:

"Поразрядные" операторы | и может использоваться для получения эффекта, но только если тип возврата - bool. Я не упоминал об этом в спецификации ANSI С++. Из того, что я могу сказать, это работает, потому что "bool" преобразуется в int (true = 1, false = 0), а затем используется побитовый оператор, затем он преобразуется обратно в bool.

Операторы "+" и "*" также могут использоваться. Это не упоминается в спецификации ANSI С++, но, вероятно, работает по той же причине, что и выше. "+" дать "или", потому что true преобразуется в 1, а затем ничего, кроме 0, преобразуется обратно в true. "*" работает для "и", потому что 1 (true) * 0 (false) == 0 (false) и 1 (true) * 1 (true) == 1 (true)

Оба они, похоже, полагаются на неявное преобразование типа в integer, а затем обратно в bool. Оба они, вероятно, испортили бы всех, кто пытается сохранить код.

Другие ответы сводятся к "Просто использовать временные" или "Реализовать свои собственные", что не было вопросом. Цель состояла в том, чтобы увидеть, был ли уже реализован оператор, реализованный в стандарте С++.

4b9b3361

Ответ 1

Оператор & выполняет логические операции "и" для операндов bool и не закорочен.

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

Я рекомендую не делать это. Использование временных переменных - лучшее решение. Не жертвуйте удобочитаемостью для "умного кода".

Ответ 2

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

Это будет "изящное" решение:). Опираясь на побочные эффекты оценочного порядка, будет далеко не изящным, склонным к ошибкам и трудно понять для следующего разработчика, который бродит по вашему проекту. Опираясь на побочные эффекты, конечно, контрастирует с чем-то вроде следующего фрагмента, который является вполне логичным и обоснованным вариантом использования только для оценки:

if ( obj != NULL && obj->foo == blah ) { /* do stuff */ }

Ответ 3

Да, для этого есть встроенные операторы. + выполняется не короткое замыкание OR и * имеет значение AND.

#include <iostream>
using namespace std;

void print(bool b)
{
    cout << boolalpha << b << endl;
}

int main() 
{
    print(true + false);
    print(true * false);
}

Выход:

True

ложно

Ответ 4

Вы можете тривиально написать свой собственный.

bool LongCircuitAnd( bool term1, bool term2 ) { return term1 && term2; }

bool Func3(int x, int y, int z, int q){
  return LongCircuitAnd( Func1(x,y), Func2(z,q) ); 

И если вы хотите быть очень причудливым, вы могли бы даже встроить его!

Хорошо, ладно, если вы действительно не хотите ужасных накладных расходов на вызов функции.

bool Func3(int x, int y, int z, int q){
  return ((int)Func1(x,y)) * ((int)Func2(z,q)); 

Но я не считаю это элегантным. Это можно предположить, что слишком умный компилятор мог бы коротко замыкать это...

Ответ 5

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

return (b1=Func1()), (b2=Func2()), (b1&&b2);

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

Другая возможность, но я бы рекомендовал против, было бы для двух функций возвращать тип, который перегружает '& &' оператор. Поскольку перегруженный оператор вызывает функцию, он всегда оценивает оба операнда, даже в случаях (например, & &), где встроенный оператор не работает - обычно это что-то вроде проблемы, но в этом случае это именно то, что вы хотите

class mybool { 
    bool value;
public:
    bool operator&&(mybool const &other) const { 
        return value && other.value;
    }
};

mybool Func1(int, int);
mybool Func2(int, int);

bool Func3(int x, int y, int z, int q) { 
    return Func1(x, y) && Func2(z,q);
}

Пока это работает, мне кажется, что это просто слишком "умный" - то, что не было бы совершенно очевидно для большинства читателей. Другое имя для mybool может помочь, но я не могу думать о том, что отражает намерение очень хорошо, не становясь настолько подробным, что это будет чистый убыток.

Ответ 6

Да. Перегруженные версии operator&& и operator|| не имеют короткого замыкания - они оценивают оба операнда, даже если левый операнд "определяет" результат... (Источник)

При этом не перегружайте operator&& или operator||. Будьте любезны вашим программистам по обслуживанию, которые будут смотреть на && или || и предположить, что они делают короткое замыкание.

Ответ 7

Для этой цели был введен почти универсальный, но часто недокументированный нестандартный оператор, впервые предложенный GCC рядом с x ?: y (x, если ненулевой else y), и теперь печально удаленный >? и <? min/max и их составные формы присваивания (см. http://gcc.gnu.org/onlinedocs/gcc/Deprecated-Features.html). К сожалению, уже с использованием & и && они, похоже, соскабливают дно ствола, чтобы найти соответствующую последовательность символов, но это только мое мнение - приветствовало бы любые исторические объяснения, почему это могло быть выбрано.

Итак, хотя в настоящее время это не так хорошо известно, как многие другие операторы, >! оператор (правильно, но скучно называемый "длинным контуром" и "разговорный" "большой узел" теми, кто находится в знать) был добавлен большинством компиляторов C и С++ (включая GCC и даже MSVС++) для удовлетворения этого требования:

bool f1() { ... }
bool f2() { ... }

...
bool f3() { return f1() >! f2(); }

Возьмите его для вращения; -).