Ответ 1
Вы можете сделать:
for (State s = loadSomething(); !s; ) return s;
но я не уверен, что он более изящный, и он определенно менее читабель...
Есть ли лучший способ для этой "идиомы"?
if(State s = loadSomething()) { } else return s;
Другими словами, я хочу что-то сделать, что может вернуть ошибку (с сообщением) или состояние успеха, и если была ошибка, я хочу ее вернуть. Это может стать очень повторяющимся, поэтому я хочу сократить его. Например
if(State s = loadFoobar(&loadPointer, &results)) { } else return s;
if(State s = loadBaz(&loadPointer, &results)) { } else return s;
if(State s = loadBuz(&loadPointer, &results)) { } else return s;
Это не должно использоваться исключения, которые я бы предпочел иначе (неподходящий для этой сборки). Я мог бы написать небольшой класс BooleanNegator<State>
, который сохраняет значение и отрицает его логическую оценку. Но я хочу избежать этого ad-hoc и предпочитаю решение для повышения/стандартизации.
Вы можете сделать:
for (State s = loadSomething(); !s; ) return s;
но я не уверен, что он более изящный, и он определенно менее читабель...
Я предполагаю, что контекст похож на
State SomeFunction()
{
if(State s = loadSomething()) { } else return s;
return do_something_else();
}
без исключения исключений, если do_something_else()
делает что-то актуальное для SomeFunction()
и возвращает State
. В любом случае, результат продолжения внутри функции должен привести к возврату State
, поскольку падение с конца приведет к тому, что вызывающий объект будет демонстрировать поведение undefined.
В этом случае я бы просто реструктурировал функцию
State SomeFunction()
{
if (State s = loadSomething())
return do_something_else();
else
return s;
}
Неявные предположения заключаются в том, что State
имеет некоторый оператор (например, operator bool()
), который может быть проверен, что копирование a State
возможно (подразумевается наличием a loadSomething()
, которое возвращает его) и относительно недорогим, и что два экземпляра State
могут существовать за один раз.
Помимо некоторых умных/хакерских видов использования разных ключевых слов для получения того же поведения или добавления дополнительных или дополнительных сложных шаблонов или макросов для получения ключевого слова unless()
или для того, чтобы каким-то образом выполнить команду !
, я ' d придерживайтесь только основных вещей.
Это одно из мест, где я (возможно) добавлю лишние "лишние" скобки:
void someFunction()
{
// some other code
{ State s = loadSomething(); if(!s) return s; }
// some other code
}
Однако в этом конкретном случае я бы расширил его, чтобы подчеркнуть ключевое слово return
, которое можно легко упустить, когда оно раздавлено на однострочный. Итак, если однострочный повтор повторяется много раз, и если он не станет очевидным, что внутри есть return
, я бы, вероятно, написал:
void someFunction()
{
// some other code
{
State s = loadSomething();
if(!s)
return s;
}
// some other code
}
Это может выглядеть как увеличение области s
, но на самом деле это эквивалентно объявлению State s
в if()
. Все благодаря дополнительным скобкам, которые явно ограничивают видимость локальных s
.
Однако некоторые люди просто "ненавидят", видя { .. }
не связанными с ключевым словом/классом/функцией/и т.д., или даже считают его нечитаемым из-за "предполагая, что ключевое слово if/while/etc было случайно удалено".
Еще одна идея пришла ко мне после добавления повторяющегося примера. Вы могли бы попробовать трюк, известный из языков сценариев, где &&
и ||
могут возвращать значения non-bool:
State s = loadFoobar(&loadPointer, &results);
s = s || loadBaz(&loadPointer, &results);
s = s || loadBuz(&loadPointer, &results);
if(!s) return s;
однако есть проблема: в отличие от языков script, в С++ такие перегрузки &&
и ||
теряют свою короткозамкнутую семантику, что делает эта попытка бессмысленна.
Однако, поскольку dyp указал на очевидную вещь, как только область s
будет увеличена, теперь можно ввести простой if
. Его видимость может быть снова ограничена дополнительными {}
:
{
State s;
if(!(s = loadFoobar(&loadPointer, &results))) return s;
if(!(s = loadBaz(&loadPointer, &results))) return s;
if(!(s = loadBuz(&loadPointer, &results))) return s;
}