How to simplify multiple if-else-if statements in c++

流过昼夜 提交于 2019-12-12 02:17:37

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!