В C++ нет нативной поддержки switch для строк, но есть 4 мощных способа это обойти! Разбираем от простого к продвинутому.
Проблема:
// ❌ Так нельзя в C++
switch(str) {
case "hello": ...
case "quit": ...
}
1️⃣ Решение: Хеширование через enum
Самый простой и быстрый способ:
enum class StringCode {
hello, quit, help, unknown
};
StringCode hashString(const string& str) {
if (str == "hello") return StringCode::hello;
if (str == "quit") return StringCode::quit;
if (str == "help") return StringCode::help;
return StringCode::unknown;
}
switch (hashString(command)) {
case StringCode::hello:
cout << "Hello there!" << endl;
break;
case StringCode::quit:
cout << "Goodbye!" << endl;
break;
}✅ Плюсы: быстро, экономно по памяти
🔸 Когда: CLI интерфейсы, конфиги
2️⃣ Решение: unordered_map + функторы
Для динамической обработки:
class CommandProcessor {
unordered_map<string, function<void()>> commands;
public:
CommandProcessor() {
commands["help"] = []() {
cout << "Help info" << endl;
};
commands["add"] = []() {
cout << "Adding..." << endl;
};
}
void execute(const string& cmd) {
auto it = commands.find(cmd);
if (it != commands.end()) {
it->second();
}
}
};✅ Плюсы: гибкость, можно менять во runtime
🔸 Когда: плагины, динамические команды
3️⃣Решение: Constexpr хеширование (C++17)
Хеширование на этапе компиляции:
constexpr uint64_t hash(string_view str) {
uint64_t hash = 0;
for (char c : str) {
hash = (hash * 131) + c;
}
return hash;
}
constexpr uint64_t operator""_hash(const char* str, size_t len) {
return hash(string_view(str, len));
}
switch (hash(action)) {
case "save"_hash:
cout << "Saving..." << endl;
break;
case "load"_hash:
cout << "Loading..." << endl;
break;
}✅ Плюсы: производительность как у int switch
🔸 Когда: нужна скорость + compile-time проверки
4️⃣Решение: String Pool (advanced)
Для высоконагруженных систем:
class StringPool {
unordered_set<string> pool;
public:
const string* intern(const string& str) {
auto [it, inserted] = pool.insert(str);
return &(*it);
}
};
// Сравниваем указатели, а не строки!
if (str == pool.intern("start")) {
// быстрее обычного сравнения строк
}✅ Плюсы: O(1) сравнение вместо O(n)
🔸 Когда: частые повторяющиеся строки
💡 Практический пример: Текстовый редактор
class TextEditor {
enum class CommandType {
insert, delete_line, move, print, unknown
};
CommandType getCommandType(const string& cmd) {
if (cmd == "insert" || cmd == "i")
return CommandType::insert;
if (cmd == "delete" || cmd == "d")
return CommandType::delete_line;
// ...
}
void executeCommand(const string& cmdLine) {
switch (getCommandType(cmd)) {
case CommandType::insert: /* ... */ break;
case CommandType::delete_line: /* ... */ break;
}
}
};Сравнение производительности:
🔸 Enum хеширование: O(1) после предобработки
🔸 unordered_map: O(1) в среднем, гибко
🔸 Constexpr hash: O(1), compile-time
🔸 String Pool: O(1), лучшее для частых операций
Выбор метода:
Небольшой фикс. набор строк → Enum hash
Динамические команды → unordered_map
Критична скорость → Constexpr hash
Много повторений → String Pool
Важные моменты ⬇️
🔸Enum подход требует exhaustive списка
🔸unordered_map имеет overhead на lookup
🔸constexpr работает только с литералами
🔸String Pool нужен для действительно частых операций
Pro-tip:
Комбинируйте подходы! Например:
🔸constexpr hash для горячих путей
🔸 unordered_map для редких команд
🔸 String pool для логирования
Реальные кейсы применения:
✅Парсеры конфигов
✅CLI приложения
✅Обработка HTTP методов
✅Игровые движки (команды консоли)
✅Компиляторы (обработка токенов)
📎 Статья
🎙 Новости
📝 База вопросов
