当您在检索值的表达式上分支时,是否有类似 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())
{
    // 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

有什么建议吗?

没有。没有这样的习语,也没有这样的语法

此外,你已经到了不值得让你的代码越来越混淆的地步了。

就这么写吧

如果您真的不想范围泄漏,请引入一个新范围:

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

我经常使用这种模式,虽然我一直被指责为范围成瘾,所以请按你的意愿使用。

在保持代码可理解的同时使用该习惯用法的唯一方法是,如果您的函数 returns 是一个可以转换为 bool 的对象,并且 true 表明您想要采用branch 和 false 意味着你不关心它。其他任何事情都只会导致只写代码。

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

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

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

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

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

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

我建议你只在 if 周围定义一个额外的块,但如果你真的想要那种确切的语法,一个解决方案可能是声明你自己的 class 包装 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

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

您可以使用 lambda。

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

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

其中 maybe_filter 接受一个 T 和一个测试函数以及 returns optional<T>。如果在 T 上评估测试函数给出 false,则 optional<T> 为空,否则 T

或者实际上,将您的错误 API 修改为 return 可选字符串。

您可以使用:

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

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