Есть ли какая-либо альтернатива использованию if-стен вместо чего-то другого в C ?

#c #if-statement #hashmap

Вопрос:

Я занимаюсь C , и мое приложение, например, принимает подкоманды ./my_app test 123 .

Я наполовину новичок в C и ничего не могу найти в Интернете, так что я не знаю, ха-ха.

Например, в python я бы сделал:

 #!/usr/bin/env python3

import sys

def test(num):
    print(f"Test {num}")

subcommands = {"test": test}

subcommands[sys.argv[1](sys.argv[2])
 

какой-нибудь C эквалайзер к этому? если да, то должен ли я использовать его или придерживаться if-else_if-else?

Комментарии:

1. Я не знаю, что такое стена «если». Какие — нибудь отношения с Ларри Уоллом?

2. @user4581301 стена оператора if = набор операторов if/else if/else, пример: pastebin.com/4nJ6QmXr

3. Придерживайтесь if сначала. Если вы действительно хотите, попробуйте std::map , std::string и std::function , но они приводят к снижению производительности.

4. В C , в отличие от Python, нет встроенной поддержки сопоставления строки с функцией. Если вам нужна такая возможность, вам необходимо ее реализовать (например, структура данных и/или код для явного сопоставления строки с указателем функции, чтобы вызвать эту функцию — и это должно быть адаптировано для приложения). Разница заключается в разных причинах, например, Python является интерпретируемым языком, в то время как C — нет.

5. @Ari157 Спасибо. Приятно это знать. Я всегда называл их «если бы лестницы».

Ответ №1:

Взгляните на std::map / std::unordered_map , например:

 #include <iostream>
#include <map>
#include <string>

void test(const std::string amp;value) {
    std::cout << "Test " << value << std::endl;
}

using cmdFuncType = void(*)(const std::string amp;);

const std::map<std::string, cmdFuncType> subcommands = {
    {"test": amp;test}
};

int main(int argc, char* argv[]) {
    if (argc != 3) {
        std::cerr << "usage: program command value" << std::endl;
        return 0;
    }

    auto iter = subcommands.find(argv[1]);
    if (iter == subcommands.end()) {
        std::cerr << "unknown command: " << argv[1] << std::endl;
        return 0;
    }

    iter->second(argv[2]);
    return 0;
}
 

Комментарии:

1. Я склонен идти std::function<void(std::stringamp;)> , а не вытаскивать void(*)(const std::string amp; . Есть ли преимущество в использовании cmdFuncType такого определения?

2. @Martin York template_instantiate_undefined: Неявный экземпляр неопределенного шаблона «std::функция<пусто>»

3. @Ari157 вы добавили #include <functional> в использование std::function ?

4. @MartinYork std::function хорош, если вы хотите использовать лямбды для записей или смешивать лямбды/функторы/функции вместе. Но если все записи будут простыми функциями, то накладные std::function расходы будут немного излишними.

5. @Remy Lebeau я сделал, но ваше решение работает, как будто оно ломается только тогда, когда я использую чистую std::функцию<void(std::stringamp;)>

Ответ №2:

Это то, чего вы пытаетесь достичь:

 #include <string>
#include <functional>
#include <iostream>
#include <map>

void test(int num) {
    std::cout << "Test " << num << "n";
}

std::map<std::string, std::function<void(int)>> subcommands = {
    {"test", test}
};

int main(int argc, char* argv[]) {

    subcommands[argv[1]](std::atoi(argv[2]));
}
 

Комментарии:

1. Ошибка сегментации 🙁

2. @Ari157 Я предполагаю, что пользователь вводит допустимые значения. Это MVP.

3. Если вы добавите проверку ошибок. Тогда это в основном выглядит так, как у Реми выше. Уйду отсюда просто потому, что это использует std::function<void(int)> , а не void(*)(int) как альтернативу.