Есть ли идиома как `if (Value * value = getValue())`, когда вы введете ответ на выражение полученного значения?
Я часто использую общий
if (Value * value = getValue())
{
// do something with value
}
else
{
// handle lack of value
}
Теперь я также часто делаю
QString error = someFunctionReturningAnErrorString(arg);
if (!error.isEmpty())
{
// handle the error
}
// empty error means: no error
Что все отлично, но я бы хотел, чтобы переменная error
была привязана к if
-блоку. Есть ли приятная идиома для этого? Очевидно, я могу просто обернуть всю часть внутри другого блока.
Это, очевидно, не работает:
if(QString error = someFunctionReturningAnErrorString(arg), !error.isEmpty())
{
// handle the error
}
// empty error means: no error
И, к сожалению (но по уважительным причинам) QString
не может быть преобразован в bool, так что это тоже не работает:
if(QString error = someFunctionReturningAnErrorString(arg))
{
// handle the error
}
// empty error means: no error
Любые предложения?
Ответы
Ответ 1
Единственный способ использовать эту идиому, сохраняя при этом код понятным, - это то, что ваша функция возвращает объект, который конвертируется в bool таким образом, что true
указывает, что вы хотите взять ветку и false
означает, что вы не заботятся об этом. Все остальное просто приведет к созданию только кода для записи.
Одним из таких объектов, который может быть релевантным, является boost::optional
. Дано:
boost::optional<QString> someFunctionReturningAnErrorString(T arg);
Вы можете использовать идиому, которую хотите, естественным образом:
if (auto error = someFunctionReturningAnErrorString(arg)) {
// ...
}
Это также имеет дополнительное преимущество, когда я считаю сообщение об ошибке optional
более семантически значимым, чем необходимость проверки пустого сообщения об ошибке.
Ответ 2
Нет. Нет такой идиомы, и нет такого синтаксиса, как это!
Кроме того, вы достигли точки, в которой уже не стоит делать ваш код все более запутанным.
Просто напишите его, как сейчас.
Если вы действительно не хотите утечки области, введите новую область:
{
const QString error = someFunctionReturningAnErrorString(arg);
if (!error.isEmpty()) {
// handle the error
}
}
// The above-declared `error` doesn't exist down here
Я использую эту схему довольно много, хотя меня довольно обвиняют в пристрастии к сфере охвата, поэтому сделайте так, как хотите.
Ответ 3
В принципе нет чистого способа сделать это.
Я бы порекомендовал вам просто определить дополнительный блок вокруг if
, но если вы действительно хотите иметь этот точный синтаксис, можно было бы объявить вашу собственную оболочку класса QString
:
struct ErrorString
{
ErrorString(QString&& s) : s{move(s)} {}
operator bool() {return !s.isEmpty();}
QString s;
};
И тогда вы можете написать:
if(ErrorString error = someFunctionReturningAnErrorString(arg))
{
// handle the error
}
// empty error means: no error
Но я не очень люблю это решение.
Ответ 4
Вы можете использовать:
for(QString error = someFunctionReturningAnErrorString(arg); !error.isEmpty(); /* too bad 'break' is invalid here */)
{
// handle the error
break;
}
но это уродливо, и ваш код трудно читать. Пожалуйста, не делайте этого.
Ответ 5
if(auto message = maybe_filter( getError(arg), [](auto&&str){
return !str.isEmpty();
}) {
}
где maybe_filter
берет T
и тестовую функцию и возвращает optional<T>
. optional<T>
пуст, если evalutating тестовая функция на T
дает false и T
в противном случае.
Или, действительно, измените вашу ошибку, получив API для возврата необязательной строки.
Ответ 6
Вы можете использовать лямбда.
auto error_string_handler = [](QString && error) {
if (error.isEmpty()) return;
//...
}
error_string_handler(someFunctionReturningAnErrorString(arg));