Enumerations are used to store a bundle of information. They have numerous applications. This Nibble will demonstrate 2 such applications.
- Returning status codes
- Implementing a simple Finite State Machine (FSM)
1. Returning status codes
Suppose a function validates a password.
A weak version might return integers:
int validatePassword(std::string_view password){
if (password.empty()) {
return -1;
}
if (password.length() < 8) {
return -2;
}
if (password == "password123") {
return -3;
}
}
This technically works, but the return values are cryptic. What does it mean to return -2?
A caller must remember what each number means:
-1 // empty?
-2 // too short?
-3 // too obvious?
0 // success?
That is fragile. The code forces the reader to translate numbers into meaning.
An enum makes the result explicit:
#include <iostream>
#include <string_view>
enum class PasswordResult {
Success,
Empty,
TooShort,
TooCommon
};
PasswordResult validatePassword(std::string_view password){
if (password.empty()) {
return PasswordResult::Empty;
}
if (password.length() < 8) {
return PasswordResult::TooShort;
}
if (password == "password123") {
return PasswordResult::TooCommon;
}
return PasswordResult::Success;
}
void printResult(PasswordResult result){
switch (result) {
case PasswordResult::Success:
std::cout << "Password accepted\\n";
break;
case PasswordResult::Empty:
std::cout << "Password cannot be empty\\n";
break;
case PasswordResult::TooShort:
std::cout << "Password is too short\\n";
break;
case PasswordResult::TooCommon:
std::cout << "Password is too common\\n";
break;
}
}
int main(){
printResult(validatePassword(""));
printResult(validatePassword("wolf"));
printResult(validatePassword("password123"));
printResult(validatePassword("StrongerPassphrase"));
}
// Terminal output:
Password cannot be empty
Password is too short
Password is too common
Password accepted
2. A simple FSM
When enums are paired with a switch/case block they produce a simple FSM, where the states are stored in the enum.
Let’s simulate a washing machine!
#include <iostream>
enum class WasherState {
Idle,
Filling,
Washing,
Draining,
Finished
};
WasherState nextState(WasherState state){
switch (state) {
case WasherState::Idle:
return WasherState::Filling;
case WasherState::Filling:
return WasherState::Washing;
case WasherState::Washing:
return WasherState::Draining;
case WasherState::Draining:
return WasherState::Finished;
case WasherState::Finished:
return WasherState::Finished;
}
return WasherState::Finished;
}
void printState(WasherState state){
switch (state) {
case WasherState::Idle:
std::cout << "Idle\\n";
break;
case WasherState::Filling:
std::cout << "Filling\\n";
break;
case WasherState::Washing:
std::cout << "Washing\\n";
break;
case WasherState::Draining:
std::cout << "Draining\\n";
break;
case WasherState::Finished:
std::cout << "Finished\\n";
break;
}
}
int main(){
WasherState state { WasherState::Idle };
for (int step { 0 }; step < 5; ++step) {
printState(state);
state = nextState(state);
}
}
// Terminal output:
Idle
Filling
Washing
Draining
Finished