"if(T t = ...) { } else return t;" 的优雅方式?

Elegant way for "if(T t = ...) { } else return t;"?

有没有更好的方法"idiom"?

if(State s = loadSomething()) { } else return s;

换句话说,我想做一些事情,这可能 return 一个错误(带有消息)或一个成功状态,如果有错误我想 return 它。这会变得非常重复,所以我想缩短它。例如

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;

这不能使用例外情况,否则我会赞成(不适合此版本)。我可以写一些 class BooleanNegator<State> 来存储值,并否定其布尔值。但我想避免临时执行此操作,而更喜欢 boost/standard 解决方案。

你可以这样做:

for (State s = loadSomething(); !s; ) return s;

但我不确定它是否更优雅,而且它的可读性肯定更差...

我假设上下文是这样的

State SomeFunction()
{
     if(State s = loadSomething()) { } else return s;
     return do_something_else();
}

不抛出异常,其中 do_something_else() 做了一些与 SomeFunction() 和 returns 和 State 相关的事情。无论哪种方式,在函数内继续的结果需要导致返回 State,因为从末尾掉下来会导致调用者表现出未定义的行为。

在那种情况下,我会简单地将函数重组为

State SomeFunction()
{
     if (State s = loadSomething())
        return do_something_else();
     else
        return s;
}

隐含的假设是 State 有一些可以测试的运算符(例如 operator bool()),复制 State 是可能的(暗示存在 loadSomething() returns 一个)并且相对便宜,State 的两个实例可以同时存在。

除了一些 smart/hacky 使用不同的关键字来获得相同的行为,或添加或多或少复杂的额外模板或宏来获得 unless() 关键字或以某种方式设法注入 ! 操作员,我会坚持基本的东西。

这是我(可能)注入额外 "unnecessary" 括号的地方之一:

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 的范围,但实际上它相当于在 if() 中声明 State s。多亏了额外的括号,它明确限制了本地 s.

的可见性

然而,有些人 "hate" 看到 { .. } 没有加上 keyword/class/function/etc,甚至认为它不可读,因为 "suggesting that a if/while/etc keyword was accidentally deleted".

添加重复示例后,我又想到了一个主意。您可以尝试使用脚本语言中已知的技巧,其中 &&|| 可能 return 一个非布尔值:

State s = loadFoobar(&loadPointer, &results);
s = s || loadBaz(&loadPointer, &results);
s = s || loadBuz(&loadPointer, &results);
if(!s) return s;

但是有一个问题:与脚本语言相比,在 C++ 中 &&|| lose their short-circuit semantics 这样的重载使得这种尝试毫无意义。

然而,正如 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;
}