问题
Suppose I have four functions for four cases:
void ac() {
//do something
}
void ad() {
//do something
}
void bc() {
//do something
}
void bd() {
//do something
}
void f(bool a, bool b, bool c, bool d) {
if(a and c) {
ac();
}
else if(a and d) {
ad();
}
else if(b and c) {
bc();
}
else if(b and d){
bd();
}
else {
throw 1;
}
}
For the 2 by 2 situation it's quite simple, but in more complex situations, this can get very tedious. Is there a way to simplify this?
回答1:
#define A 0x1
#define B 0x2
#define C 0x4
#define D 0x8
void f(bool a, bool b, bool c, bool d) {
int mask = 0;
if( a ) mask |= A;
if( b ) mask |= B;
if( c ) mask |= C;
if( d ) mask |= D;
// Alternative is to use mask as a subscript in an array of function pointers.
switch( mask ) {
case A|C: ac(); break;
case A|D: ad(); break;
case B|C: bc(); break;
default: bd(); break;
}
}
回答2:
Brian's answer tempted me. I had a very hard time calling this "more concise". So I figured, I should be able to arrive at something like:
void f(bool a, bool b, bool c, bool d) {
switch(combine(a, b, c, d))
{
case combine(1,0,1,0): ac(); break;
case combine(1,0,0,1): ad(); break;
case combine(0,1,1,0): bc(); break;
default: bd(); break;
}
}
And, with the magic of constexpr
it can be done: Live On Coliru
Demo program:
#include <iostream>
#include <iomanip>
#include <limits>
#include <cstdint>
namespace detail
{
// a little overkill to have a functor here too, but it's a good habit™
template <typename T = uintmax_t>
struct to_bitmask_f
{
template <typename... Flags> struct result { typedef T type; };
template <typename... Flags>
typename result<Flags...>::type
constexpr operator()(Flags... flags) const {
static_assert(sizeof...(Flags) < std::numeric_limits<uintmax_t>::digits, "Too many flags for integral representation)");
return impl(flags...);
}
private:
constexpr static inline T impl() { return {}; }
template <typename... Flags>
constexpr static inline T impl(bool b, Flags... more) {
return (b?1:0) + (impl(more...) << (T(1)));
}
};
}
template <typename T = uintmax_t, typename... Flags>
constexpr T combine(Flags... flags)
{
return detail::to_bitmask_f<T>()(flags...);
}
void ac() { std::cout << "ac\n"; }
void ad() { std::cout << "ad\n"; }
void bc() { std::cout << "bc\n"; }
void bd() { std::cout << "bd\n"; }
void f(bool a, bool b, bool c, bool d) {
switch(combine(a, b, c, d))
{
case combine(1,0,1,0): ac(); break;
case combine(1,0,0,1): ad(); break;
case combine(0,1,1,0): bc(); break;
default: bd(); break;
}
}
int main()
{
f(1,0,1,0);
f(1,0,0,1);
f(0,1,1,0);
f(0,1,0,1);
// others:
f(0,1,1,1);
f(1,1,1,1);
f(0,0,0,0);
}
Printing out:
ac
ad
bc
bd
bd
bd
bd
回答3:
How about a 3 dimensional function pointer array?
const void (*func[2][2][2][2]) = { { { {allFalse, aFalseBFalseCFalseDTrue}, {AllButCFalse, AllButCandDFalse}... } } };
void f(bool a, bool b, bool c, bool d) {
func[a][b][c][d]();
}
You could combine this with masking like @brianbeuning used:
const void (*func[1 << 4]);
void initArray() {
func[0] = allFalse;
func[1 << 0] = allFalseButD;
func[1 << 1] = allFalseButC;
func[1 << 0 | 1 << 2] = DandCTrue;
// ...
}
void f(bool a, bool b, bool c, bool d) {
func[a << 3 | b << 2 | c << 1 | d << 0]();
}
来源:https://stackoverflow.com/questions/22596566/how-to-simplify-multiple-if-else-if-statements-in-c