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

问题描述

我的同事写了一个很长的 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 似乎不能接受可变参数函数

还有其他方法吗?

解决方法

std::any 将成为您的朋友。再加上一些包装类和包装类中的模板函数,隐藏any cast,会更直观一些。

它会给你更多的可能性。

请看:

#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 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,2,std::string("3"));

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

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

你可以像 lambda 那样包装

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); } },[str](int a,int b) { func2(a,b,str); } },...
    };

    m[type](a,b);
}