Switch для string

Рейтинг: 1Ответов: 3Опубликовано: 22.03.2011

Задача: юзер вводит команды, программа их выполняет. Хотел использовать switch, но он не хочет обрабатывать переменную типа string, только int.

Вот часть кода:

while (command == "NULL")
{
    cout << '>';
    cin >> command;
}

if (command == "exit")
{
    exit = 1;
}

if (command == "map")
{
    view_map (map, POLE);
}

if (command == "goto")
{
    string direction;
    int steps;
    cin >> direction >> steps;
    if (steps < 0)
        cout << "И каk ета па твоиму?" << endl;

    if (direction == "left")
        HeroCoord_x = HeroCoord_x - steps;

    if (direction == "right")
        HeroCoord_x = HeroCoord_x + steps;

    if (direction == "up")
        HeroCoord_y = HeroCoord_y - steps;

    if (direction == "down")
        HeroCoord_y = HeroCoord_y + steps;

    if ((HeroCoord_x < 0) || (HeroCoord_x > POLE) || (HeroCoord_y < 0) || (HeroCoord_y > POLE))
    {
        cout << "Нипалушайтсанах!" << endl;
        if (direction == "left")
            HeroCoord_x = HeroCoord_x + steps;

        if (direction == "right")
            HeroCoord_x = HeroCoord_x - steps;

        if (direction == "up")
            HeroCoord_y = HeroCoord_y + steps;

        if (direction == "down")
            HeroCoord_y = HeroCoord_y - steps;
    }
    else
    {
        make_map (map, POLE);
        go_to (map, HeroCoord_x, HeroCoord_y);
    }
}

Как реализовать это проще?

Ответы

▲ 5Принят

Можно сделать маппинг handler-ов и использовать его. Что-то вроде:

struct Handler {
    void handle() = 0;
    virtual ~Handler() {}
};

struct ExitHandler : public Handler {
    void handle() {
        //code here
    }
};

struct MapHandler  : public Handler {
    void handle() {
        //code here
    }
};

struct GotoHandler  : public Handler {
    void handle() {
        //code here
    }
};

//====================

std::map<std::string, Handler*> handlers;
handlers["exit"] = new ExitHandler();
handlers["goto"] = new GotoHandler();
handlers["map"] = new MapHandler();

//-----------------------

while (command == "NULL")
{
    cout << '>';
    cin >> command;
}
handlers[command]->handle();

Это конечно черновая и небезопасная реализация, но смысл я думаю понятен.

▲ 13

Можно использовать отображение строк в числа:

std::map <std::string, int> mapping;

mapping["left"]  = LEFT;
mapping["up"]    = UP;
mapping["right"] = RIGHT;
mapping["down"]  = DOWN;

switch (mapping[command]) {
    case LEFT:  doLeft();  break;
    case UP:    doUp();    break;
    case RIGHT: doRight(); break;
    case DOWN:  doDown();  break;
}

где LEFT, UP, RIGHT, DOWN - произвольные числа.

▲ 6

Если не опасаться коллизий, то можно использовать constexpr функции из С++11, и делать switch по хешам строк.

// FNV-1a hash, 32-bit 
inline constexpr std::uint32_t fnv1a(const char* str, std::uint32_t hash = 2166136261UL) {
    return *str ? fnv1a(str + 1, (hash ^ *str) * 16777619ULL) : hash;
}

int main() {
    std::string s = "bb";

    switch (fnv1a(s.c_str())) {
    case fnv1a("a"): std::cout << "A\n"; break;
    case fnv1a("bb"): std::cout << "B\n"; break;
    case fnv1a("ccc"): std::cout << "C\n"; break;
    };    
}