当您在检索到的值的表达式上进行分支时,是否有像“if (Value * value = getValue())”这样的成

Is there an idiom like `if (Value * value = getValue())` when you branch on an expression of the retrieved value?

本文关键字:if Value value getValue 是否 表达式 检索 分支      更新时间:2023-10-16

我经常使用公共

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不能转换为布尔值,所以这也不起作用:

if(QString error = someFunctionReturningAnErrorString(arg))
{
    // handle the error
}
// empty error means: no error

有什么建议吗?

No.没有这样的成语,也没有这样的语法

此外,您已经到了不再值得使您的代码越来越模糊的地步。

只需像现在一样编写即可。

如果您真的不希望示波器泄漏,请引入一个新的示波器:

{
   const QString error = someFunctionReturningAnErrorString(arg);
   if (!error.isEmpty()) {
      // handle the error
   }
}
// The above-declared `error` doesn't exist down here

经常使用这种模式,尽管我被指责为范围成瘾,所以随心所欲。

使用该

习惯用法同时保持代码可理解的唯一方法是,如果您的函数返回一个可转换为 bool 的对象,该对象true表示您想要获取分支,false表示您不关心它。其他任何事情都会导致只写代码。

一个可能相关的对象恰好是boost::optional。鉴于:

boost::optional<QString> someFunctionReturningAnErrorString(T arg);

你可以以自然的方式使用你想要的成语:

if (auto error = someFunctionReturningAnErrorString(arg)) {
    // ...
}

这也有一个额外的好处,我认为optional错误消息比必须检查空错误消息在语义上更有意义。

基本上没有干净的方法可以做到这一点。

我建议你在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

但我不是特别喜欢这个解决方案。

您可以使用:

for(QString error = someFunctionReturningAnErrorString(arg); !error.isEmpty(); /* too bad 'break' is invalid here */)
{
    // handle the error
    break;
}

但这很丑陋,并且使您的代码难以阅读。所以请不要。

if(auto message = maybe_filter( getError(arg), [](auto&&str){
  return !str.isEmpty();
}) {
}

其中maybe_filter采用T和测试函数并返回optional<T>。 如果评估T上的测试函数会给出 false,则optional<T>为空,否则T

或者实际上,修改获取 API 的错误以返回可选字符串。

您可以使用 lambda。

auto error_string_handler = [](QString && error) {
    if (error.isEmpty()) return;
    //...
}
error_string_handler(someFunctionReturningAnErrorString(arg));