Что тут происходит?
if(int a = Func1())
{
// Works.
}
if((int a = Func1()))
{
// Fails to compile.
}
if((int a = Func1())
&& (int b = Func2()))
)
{
// Do stuff with a and b.
// This is what I'd really like to be able to do.
}
В разделе 6.4.3 стандарта 2003 объясняется, как переменные, объявленные в условии оператора выбора, имеют область видимости, которая распространяется до конца подзапросов, контролируемых этим условием. Но я не вижу, где говорится что-либо о невозможности заключить объявление в круглые скобки, и при этом ничего не говорится об одном объявлении на условие.
Это ограничение раздражает даже в тех случаях, когда требуется только одно объявление в условии. Учти это.
bool a = false, b = true;
if(bool x = a || b)
{
}
Если я хочу войти в область 'if "-body с x, установленным в false, тогда для объявления нужны круглые скобки (поскольку оператор присваивания имеет более низкий приоритет, чем логическое ИЛИ), но поскольку скобки не могут использоваться, для него требуется объявление x вне тело, передавая это объявление в более широкую область видимости, чем требуется. Очевидно, что этот пример тривиален, но более реалистичным будет тот, где a и b - функции, возвращающие значения, которые необходимо протестировать
Итак, что я хочу сделать в соответствии со стандартом, или мой компилятор просто ломает мои яйца (VS2008)?
if
.if
это не цикл, это условный.while
такие же, как и дляif
.if (int a = foo(), int b = bar(), a && b)
:? Если оператор запятой не перегружен, стандарт говорит, что выражения оцениваются слева направо, а результатом является последнее выражение. Он работает сfor
инициализацией циклов, почему не здесь?if
работает, и это кажется неправильным предположением.Ответы:
Начиная с C ++ 17, наконец, возможно то, что вы пытались сделать :
Обратите внимание на использование
;
вместо вместо,
объявления объявления и фактического условия.источник
Я думаю, вы уже намекнули на проблему. Что компилятору делать с этим кодом?
Оператор «&&» представляет собой логическое И при коротком замыкании. Это означает, что если первая часть
(1==0)
окажется ложной, тогда вторая часть(bool a = false)
не должна оцениваться, потому что уже известно, что окончательный ответ будет ложным. Если(bool a = false)
не оценивается, что потом делать с кодом, который используетa
? Не могли бы мы просто инициализировать переменную и оставить ее неопределенной? Будем ли мы инициализировать его по умолчанию? Что, если бы тип данных был классом, и это имело бы нежелательные побочные эффекты? Что, если бы вместо этогоbool
вы использовали класс и у него не было конструктора по умолчанию, так что пользователь должен был указать параметры - что нам тогда делать?Вот еще один пример:
Похоже, что обнаруженное вами ограничение кажется вполне разумным - оно предотвращает возникновение подобных двусмысленностей.
источник
Условие в
if
илиwhile
заявление может быть либо выражение , либо одной переменной декларации (с инициализацией).Ваши второй и третий примеры не являются ни допустимыми выражениями, ни действительными объявлениями, поскольку объявление не может быть частью выражения. Хотя было бы полезно написать код, подобный вашему третьему примеру, это потребует значительного изменения синтаксиса языка.
Спецификация синтаксиса в 6.4 / 1 дает следующее условие:
указание единственного объявления без скобок или других украшений.
источник
Если вы хотите заключить переменные в более узкую область, вы всегда можете использовать дополнительные
{ }
источник
Последний раздел уже работает, вам просто нужно написать его немного иначе:
источник
Вот уродливый обходной путь с использованием цикла (если обе переменные - целые числа):
Но это запутает других программистов, и это довольно плохой код, поэтому не рекомендуется.
Простой охватывающий
{}
блок (как уже рекомендовано) читать намного легче:источник
Следует также отметить, что выражения внутри большего блока if
не обязательно гарантируют, что они будут оцениваться слева направо. Одна довольно тонкая ошибка, которая у меня была в тот день, была связана с тем, что компилятор на самом деле тестировал справа налево, а не слева направо.
источник
if(p && p->str && *p->str) ...
. Справа налево было бы смертельно опасно и не хитро. С другими операторами - даже присваивание! - и аргументы вызова функции вы правы, но не с операторами короткого замыкания.С помощью небольшой магии шаблонов вы можете как бы обойти проблему невозможности объявления нескольких переменных:
(Обратите внимание, это теряет оценку короткого замыкания.)
источник