假设我有四种情况的四种功能:
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的情况非常简单,但在更复杂的情况下,这会变得非常乏味。有没有一种方法可以简化?
#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;
}
}
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
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]();
}