如何使用一张地图存储不同的功能

How to use one map to store different function

我的同事写了一个很长的 switch-case 函数,如下所示:

void func(int type, int a, int b) {
    std::string str = "hello";
    switch (type) {
        case 1: {
            func1(a, b);
            break;
        }
        case 2: {
            func2(a, b, str);
            break;
        }
        // hundreds of cases...
    }
}

我想改变这个糟糕的功能,因为它有太多的情况。

好消息是每个case只调用一个函数,它必须使用ab作为它的第一个和第二个参数。坏消息是其中一些可能需要第三个参数。

我在想是否可以使用 std::map<int, std::function<void(int, int, ...)>> 来存储案例中的所有功能,但它不起作用。 std::function 似乎不能接受可变函数。

还有其他方法吗?

你可以像这样包装成 lambdas

void func(int type, int a, int b) {    
    std::string str = "hello";

    std::map<int, std::function<void(int, int)>> m {
        {1, [](int a, int b) { func1(a, b); } },
        {2, [str](int a, int b) { func2(a, b, str); } },
        ...
    };

    m[type](a, b);
}

std::any 会成为你的朋友。连同一些包装器 class 和包装器中的模板函数 class,以隐藏任何转换,这将更加直观。

而且它会给你更多的可能性。

请看:

#include <iostream>
#include <map>
#include <string>
#include <any>
#include <utility>

class Caller
{
    std::map<int, std::any> selector;
public:
    Caller() : selector() {}

    Caller(std::initializer_list<std::pair<const int, std::any>> il) : selector(il) {}
    template<typename Function>
    void add(int key, Function&& someFunction) { selector[key] = std::any(someFunction); };

    template <typename ... Args>
    void call(int key, Args ... args) {
        if (selector.find(key) != selector.end()) {
            std::any_cast<std::add_pointer_t<void(Args ...)>>(selector[key])(args...);
        }
    }
};

// Some demo functions
void a(int x) { 
    std::cout << "a\t" << x << '\n'; 
};
void b(int x, int y) {
    std::cout << "b\t" << x << '\t' << y << '\n';
};
void c(int x, int y, std::string z) {
    std::cout << "c\t" << x << '\t' << y << '\t' << z << '\n';
};
void d(std::string s, int x, int y, int z) {
    std::cout << "d\t" << s << '\t' << x << '\t' << y << '\t' << z << '\n';
};


// Definition of our caller map (using initializer list)
Caller caller{
    {1, a},
    {2, b},
    {3, c} };

int main() {

    // Some demo calls
    caller.call(1, 1);
    caller.call(2, 1, 2);
    caller.call(3, 1, 2, std::string("3"));

    // Adding an additional function
    caller.add(4, d);

    // And call this as well.
    caller.call(4, std::string("ddd"), 1,2,3);
    return 0; 
}