branching based on two boolean variables
Suppose I have two boolean variables, and I want to do completely different things based on their values. What is the cleanest way to achieve this?
Variant 1:
if (a && b)
{
// ...
}
else if (a && !b)
{
// ...
}
else开发者_如何学Python if (!a && b)
{
// ...
}
else
{
// ...
}
Variant 2:
if (a)
{
if (b)
{
// ...
}
else
{
// ...
}
}
else
{
if (b)
{
// ...
}
else
{
// ...
}
}
Variant 3:
switch (a << 1 | b)
{
case 0:
// ...
break;
case 1:
// ...
break;
case 2:
// ...
break;
case 3:
// ...
break;
}
Variant 4:
lut[a][b]();
void (*lut[2][2])() = {false_false, false_true, true_false, true_true};
void false_false()
{
// ...
}
void false_true()
{
// ...
}
void true_false()
{
// ...
}
void true_true()
{
// ...
}
Are variants 3 and 4 too tricky/complicated for the average programmer? Any other variants I have missed?
The first variant is the clearest and most readable, but it can be adjusted:
if (a && b) {
// ...
} else if (a) { // no need to test !b here - b==true would be the first case
// ...
} else if (b) { //no need to test !a here - that would be the first case
// ...
} else { // !a&&!b - the last remaining
// ...
}
You forgot about:
if (a) a_true(b);
else a_false(b);
which is probably the best choice when appliable, and when you truly need 4 different behaviours.
If you have more than 2 bools, I take this as a code smell if I have 2^n different behaviours which don't factorize well like the above. Then I may think about doing:
enum { case1, case2, ... }
int dispatch_cases(bool a, bool b, bool c, ..., bool z);
switch (dispatch_cases(a, b, ..., z))
{
case case1:
...
};
but without context, it is hard to tell whether such complexity is necessary.
IMHO, I will go for variant 3
. Because personally, I don't like if/else
when I am checking for equality. It clearly states that there are only 4 possibilities.
One minor edit would be:
inline int STATES(int X, int Y) { return (X<<1) | Y; }
// ...
switch (STATES(a,b))
To make it more fancy, you may replace 0,1,2,3
with an enum
as well.
enum States {
NONE,
ONLY_B.
ONLY_A,
BOTH
};
For just two booleans, any of them is good and reasonable. One can choose based on his taste.
However, if there are more than two booleans, say four booleans, then I personally would go with lookup table, and I would do this as:
typedef void (*functype)();
//16 functions to handle 16 cases!
void f0() {}
void f1() {}
//...so on
void f15() {}
//setup lookup table
functype lut[] =
{
f0, //0000 - means all bool are false
f1, //0001
f2, //0010
f3, //0011
f4, //0100
f5, //0101
f6, //0110
f7, //0111
f8, //1000
f9, //1001
f10, //1010
f11, //1011
f12, //1100
f13, //1101
f14, //1110
f15 //1111 - means all bool are true
};
lut[MakeInt(b1,b2,b3,b4)](); //call
MakeInt()
is easy to write:
int MakeInt(bool b1, bool b2, bool b3, bool b4)
{
return b1 | (b2<<1) | (b3 <<2) | (b4<<3);
}
精彩评论