You can use the bits in an unsigned int to declare properties, and combine those properties to define masks. A dispatch function uses the x value and a flag value to test the bits and respond accordingly.
#include <cstdint>
#include <iostream>
// Properties
static constexpr const auto C1 = 1u << 0;
static constexpr const auto C2 = 1u << 1;
static constexpr const auto C3 = 1u << 2;
static constexpr const auto C4 = 1u << 3;
static constexpr const auto C5 = 1u << 4;
static constexpr const auto C6 = 1u << 5;
// Masks (combination of properties)
static constexpr const auto C2C3 = C2 | C3;
static constexpr const auto C2C4 = C2 | C4;
// Dispatch operation based on flag (will jump, not branch)
int dispatch(int x, std::uint32_t flags) {
switch (flags) {
case C1:
return x + 1;
case C2:
return x + 4;
case C2C3:
return x + 2;
case C2C4:
return x + 3;
case C5:
return x + 5;
case C6:
return x + 6;
// add more cases as needed...
default:
// anything not specified is considered an error
throw std::runtime_error("invalid flags");
}
}
#define ASSERT(pred) \
do { \
if (!(pred)) { \
std::cerr << "expected " #pred "\n"; \
} else { \
std::cout << "ok " #pred "\n"; \
} \
} while (false)
#define EXPECT_THROW(pred) \
do { \
bool thrown = false; \
try { \
std::cout << (pred) << "\n"; \
} catch (...) { \
thrown = true; \
} \
if (thrown) { \
std::cout << "ok " #pred "\n"; \
} else { \
std::cerr << "exception not thrown in " #pred "\n"; \
} \
} while (false)
int main() {
// Only these should succeed
ASSERT(dispatch(0, C1) == 1);
ASSERT(dispatch(0, C2) == 4);
ASSERT(dispatch(0, C2C3) == 2);
ASSERT(dispatch(0, C2C4) == 3);
ASSERT(dispatch(0, C5) == 5);
ASSERT(dispatch(0, C6) == 6);
// Anything else should be a failure (there are 2^6 = 64 combinations and only
// 6 should succeed)... only a few are presented
EXPECT_THROW(dispatch(0, C1 | C2));
EXPECT_THROW(dispatch(0, C1 | C3));
EXPECT_THROW(dispatch(0, C3 | C4));
EXPECT_THROW(dispatch(0, C3));
}
Sample run:
$ clang++ example.cpp -std=c++2a -Wall -Wextra
$ ./a.out
ok dispatch(0, C1) == 1
ok dispatch(0, C2) == 4
ok dispatch(0, C2C3) == 2
ok dispatch(0, C2C4) == 3
ok dispatch(0, C5) == 5
ok dispatch(0, C6) == 6
ok dispatch(0, C1 | C2)
ok dispatch(0, C1 | C3)
ok dispatch(0, C3 | C4)
ok dispatch(0, C3)
The dispatch function can be easily modified to add more cases. It would be more beneficial if the properties/flags had a more meaningful name.