我试图找出简化以下形式的条件语句的最佳方法:
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
{
...
}
}
}
这个版本避免了任何重复和不必要的条件被评估,但写作非常冗长和痛苦。
所以我希望有一些更简单但同样有效的方式来编写它,我没想到......?
答案 0 :(得分:3)
bool a = A(), b, c, d;
if (((b = B()) && a) || ((c = C()) && b) || (d = D() && c) || ...) {
// code;
}
如果a
为false,则评估B()
以进行下一次条件检查。在第二个条件中,如果b
为false,则会评估C()
的下一个条件。通过这种方式,我们可以确保在需要时评估每个功能。但是对于最后一个条件,我们应该使用函数求值作为第二个操作数。
答案 1 :(得分:2)
这与adjacent_find
非常相似,但使用adjacent_find
则需要重新评估A
,B
等。我们可以编写我们自己的版本,通过自定义谓词来处理这个问题,而不是“比较相等”:
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;
}
如果A
,B
,C
,...都可以是相同类型的函数指针,则可以这样使用:
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会工作。
答案 2 :(得分:1)
您可以在if
。
bool b,c;
if (((b = B()) && A()) || ((c = C()) && b) || (c && D()) ) {
cout << "done";
}
正如@abdullah指出的那样,由于快捷方式评估,在b
之后的条件中使用变量||
时,可能不会初始化变量&&
。因此,结果将在以后重用的表达式必须位于int
- 运算符的左侧,这可能会引入不必要的求值。
避免这种情况的一种方法是使用三态逻辑,其中变量“知道”它是否已被分配。 C ++没有三态布尔值,但可以通过数据类型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";
}
轻松模拟:
{{1}}
答案 3 :(得分:0)
一个版本涉及将所有函数保存到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 });
}
答案 4 :(得分:0)
使用模板元编程解决问题!
//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);
}