如何在c ++中简化多个if-else-if语句

问题描述 投票:0回答:3

假设我有四种情况的四种功能:

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;
    }
}

对于2比2的情况非常简单,但在更复杂的情况下,这会变得非常乏味。有没有一种方法可以简化?

c++ control-flow
3个回答
8
投票
#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;
    }
}

3
投票

Brian的回答很吸引我。我很难称呼它为“更简洁”。所以我想,我应该能够得出类似的结果:

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;
    }
}

而且,借助constexpr的魔力,可以做到:[Live On Coliru

演示程序:

#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);
}

打印输出:

ac
ad
bc
bd
bd
bd
bd

0
投票

3维函数指针数组如何?

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]();
}

您可以将其与使用@brianbeuning这样的蒙版结合使用:

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]();
}
© www.soinside.com 2019 - 2024. All rights reserved.