Я разрабатываю инструмент, который будет работать с MPI, этот инструмент будет использовать несколько функций, и каждая функция может полностью отличаться друг от друга, например сигнатура и количество параметров. Версия C ++ ...

1
Andres 14 Янв 2021 в 18:39

1 ответ

Лучший ответ

Вы можете использовать std::apply для передачи кортежа в качестве аргументов функции.

Для хранения функций нужно какое-то стирание типа. В этом примере я выбрал std::any.

Для хранения функций с идентификатором я использовал std :: map.

#include <iostream>
#include <functional>
#include <any>
#include <map>
#include <tuple>

int foo(int val) {
    return val;
}

float bar(float val1, int val2) {
    return val1 * val2;
}

void zor(int i) {
    std::cout << i << '\n';
}

struct FuncCollection {
    std::map<int, std::function<std::any(std::any)>> funcMap;

    template <typename Ret, typename... Args>
    void addFunc(int id, Ret (*fPtr)(Args...)) {
        funcMap[id] = [=](std::any args) -> std::any {
            auto tuple = std::any_cast<std::tuple<Args...>>(args);
            if constexpr(std::is_same_v<Ret, void>) {
                std::apply(fPtr, tuple);
                return 0;
            } else {
                return std::apply(fPtr, tuple);
            }
        };
    }

    template <typename... Args>
    auto callFunc(int id, std::tuple<Args...> args) {
        return funcMap[id](args);
    }
};

int main()
{
    FuncCollection fc;
    fc.addFunc(1, foo);
    fc.addFunc(2, bar);
    fc.addFunc(3, zor);

    std::tuple<int> p1{1};
    std::tuple<float, int> p2{3.14, 2};
    std::tuple<int> p3{5};

    auto r1 = fc.callFunc(1, p1);
    auto r2 = fc.callFunc(2, p2);
    fc.callFunc(3, p3);

    std::cout << std::any_cast<int>(r1) << ' ' << std::any_cast<float>(r2) << '\n';
}

Это всего лишь пример, и в нем особенно не хватает проверок ошибок. std::any_cast вызовет исключение при недопустимом приведении.

1
super 14 Янв 2021 в 16:24