繁体   English   中英

简化重叠和条件语句

[英]Simplify overlapping And condition statements

我试图找出简化形式的条件语句的最佳方法:

if( ( A() && B() ) || ( B() && C() ) || ( C() && D() ) || .... )
{
    code
}

A / B / C / D / etc函数相对昂贵,因此将它们分别调用两次并不理想。

我想到了两种选择:

bool a = A();
bool b = B();
bool c = C();
bool d = D();
if( ( a && b ) || ( b && c ) || ( c && d ) || .... )
{
    code
}

这个版本并不理想,因为即使A()和B()都为真,每次都会评估C(),D()和任何其他条件。 在原始版本中,在这种情况下根本不会调用它们。

bool b = B();
if( ( A() && b ) )
{
    code
}
else
{
    bool c = C();
    if( ( b && c ) )
    {
        code
    }
    else
    {
        bool d = D();
        if( ( c && D ) )
        {
            code
        }
        else
        {
            ...
        }
    }
}

这个版本避免了任何重复和不必要的条件被评估,但是编写起来非常冗长和痛苦。

因此,我希望有一种我不介意的更简单但同样有效的书写方式……?

bool a = A(), b, c, d;
if (((b = B()) && a) || ((c = C()) && b) || (d = D() && c) || ...) {
    // code;
}

在这里,如果a为假,则对B()进行评估以进行下一个条件检查。 在第二个条件中,如果b为假,则评估C()的下一个条件。 这样,我们可以确保在需要时对每个函数进行评估。 但是对于最后一个条件,我们应该使用函数求值作为第二个操作数。

这非常类似于adjacent_find ,但使用adjacent_find将需要重新评估AB有时,等等。 我们可以编写自己的版本来处理此问题,方法是在谓词上进行自定义,而不是“比较相等”:

template <typename FwdIter, typename Pred>
FwdIter find_if_consecutive(FwdIter cur, FwdIter last, Pred pred) {
    if (cur == last) return last;

    bool curMatches = false, nextMatches = pred(*cur);

    for (auto next = std::next(cur); next != last; ++cur, ++next) {
        curMatches = std::exchange(nextMatches, pred(*next));
        if (curMatches && nextMatches) return cur;
        // Note: this *might* possibly be faster by moving
        // forward by 2 when `nextMatches` is false, which
        // avoids one of the `curMatches && nextMatches`.
        // Implementation left as an exercise for the reader.
    }

    return last;
}

如果ABC ,...可以都是相同类型的函数指针,则可以这样使用:

auto fns = { A, B, C, D }; // Create an initializer_list

return fns.end()
    != find_if_consecutive(fns.begin(), fns.end(), [](auto f) { return f(); });

在魔盒上直播


如果我们不能将不同的表达式放入同构类型中,则需要一个异构算法库。 Boost Hana也许会工作。

您可以在if使用赋值表达式。

bool b,c;
if (((b = B()) && A()) || ((c = C()) && b) || (c && D()) )    {
    cout << "done";
}

正如@abdullah指出的那样,必须注意由于快捷方式求值,当在||之后的条件中使用变量b可能未初始化变量b 因此,结果的表达式将在以后重用,必须位于&&运算符的左侧,这可能会引入不必要的评估。

避免这种情况的一种方法是使用三态逻辑,其中变量“知道”是否已分配。 C ++没有三态布尔值,但是可以通过数据类型int轻松模拟它:

int a = A();
int b=-1;
int c=-1;
int d=-1;

if(
   ( a && (b=B()) ) || ( (b<0?b=B():b) && (c=C()) ) || ( (c<0?c=C():c) && (d=D()) )
   )
{
    cout << "done";
}

一种版本涉及将所有功能保存到std::vector<std::function<bool()>> ,这创建了非常简单的调用约定并简化了逻辑:

#include<vector>
#include<functional>
#include<iostream>

bool evaluate_vec(std::vector<std::function<bool()>> const& funcs) {
    bool a, b;
    for (size_t index = 0; index < funcs.size(); index++) {
        //We'll ping-pong between the two cached evaluations of the variables
        if ((index & 1) == 0)
            a = funcs[index]();
        else
            b = funcs[index]();
        if (index > 0)
            //The short-circuiting behavior we intend to have
            if (a && b)
                return true;
    }
    return false;
}

int main() {
    bool evaluation = evaluate_vec({ A, B, C, D });
}

用模板元编程解决问题!

//If we run out of functions and didn't find a pair that both returned true, we return false
bool evaluate_impl(bool) {
    return false;
}

//At this point, we're guaranteed to have at least 1 cached result and 1 unevaluated function call.
template<typename Func, typename ... Funcs>
bool evaluate_impl(bool cached, Func && func, Funcs&& ... funcs) {
    //store the result of the function
    bool result = func();
    if (cached && result)
        return true;
    else {
        //the result of this call becomes the new cached value
        return evaluate_impl(result, std::forward<Funcs>(funcs)...);
    }
}

//We receive all the functions
template<typename Func, typename ... Funcs>
bool evaluate_tmp(Func && func, Funcs&& ... funcs) {
    //We cache the result of calling the first function and pass along to the next step
    return evaluate_impl(func(), std::forward<Funcs>(funcs)...);
}

int main() {
    bool result = evaluate_tmp(A, B, C, D);
}

它可以有效地扩展以支持任意数量的函数调用(无论如何编译器都可以支持)。

int main() {
    bool result = evaluate_tmp(A, B, A, C, A, A, A, A, D, A, B, A, C, A, D, A);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM