You asked about "exclusive" cases, but the issue with the conditions A == 5
and B == 7
is that they are not exclusive; they are independent.
For full generality you may need to test and handle all four cases:
if(A == 5) {
if(B == 7) {
/* case 1 */
} else {
/* case 2 */
}
} else {
if(B == 7) {
/* case 3 */
} else {
/* case 4 */
}
}
This is the notorious "bushy" if/else block. It's notorious because it can almost immediately become nearly impossible for a reader to follow, especially if the cases are involved, or more levels are introduced. (I think most style guides will tell you never to use an if/else tree that's 3 or more levels deep. I'd certainly say that.)
I have occasionally used these two alternatives:
(1) Fully decouple the cases:
if(A == 5 && B == 7) {
/* case 1 */
} else if(A == 5 && B != 7) {
/* case 2 */
} else if(A != 5 && B == 7) {
/* case 3 */
} else if(A != 5 && B != 7) {
/* case 4 */
} else {
/* can't happen */
}
The point here is to make it maximally clear to a later reader exactly which conditions go with cases 1, 2, 3, and 4. For this reason, you might as well list the last, else if(A != 5 && B != 7)
case explicitly (as I've shown), even though by that point it's basically an "else".
(2) Contrive a "two level" switch. I can't say this is a common technique; it has a whiff of being "too clever", but it's robust and readable, in its way:
#define PAIR(b1, b2) (((b1) << 8) | (b2))
switch(PAIR(A == 5), (B == 7)) {
case PAIR(TRUE, TRUE):
/* case 1 */
break;
case PAIR(TRUE, FALSE):
/* case 2 */
break;
case PAIR(FALSE, TRUE):
/* case 3 */
break;
case PAIR(FALSE, FALSE):
/* case 4 */
break;
}
I wouldn't recommend this when the conditions are A == 5
and B == 7
, because when you're down in the switch, it's not obvious what "TRUE" and "FALSE" mean, but sometimes, this sort of thing can read cleanly. It's also cleanly amenable to 3 or more levels of nesting, unlike "bushy" if/else trees, which as I said are notoriously unreadable.