当您在检索值的表达式上分支时,是否有类似 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;
}
但这很丑陋,并且使您的代码难以阅读。所以请不要。
我经常使用普通的
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;
}
但这很丑陋,并且使您的代码难以阅读。所以请不要。