C++ std::function variable with varying arguments

后端 未结 6 1476
天涯浪人
天涯浪人 2020-12-28 09:12

In my callback system I want to store std::function (or something else) with varying arguments.

Example:

  1. I want to call void()
6条回答
  •  感情败类
    2020-12-28 10:11

    Well, if you can use RTTI, you can define a MultiFuncObject like this, and you can easily bind other functions. Also, you can easily call them. But unfortunately, this approach only works for a limited number of arguments. But actually boost::bind also supports limited number of arguments (by default 9). So you can extend this class to satisfy your needs.

    Before giving you the source of MultiFuncObject, I want to show you how you can use it. It takes an template argument to be used as return type. You can bind new functions with += operator. With some template magic, the class distinguishes differences between bound functions with same count of arguments with at least one different argument type.

    You need C++11, because MultiFuncObject uses std::unordered_map and std::type_index.

    Here is usage:

    #include 
    using namespace std;
    
    void _1() {
      cout << "_1" << endl;
    }
    
    void _2(char x) {
      cout << "_2" << " " << x << endl;
    }
    
    void _3(int x) {
      cout << "_3" << " " << x << endl;
    }
    
    void _4(double x) {
      cout << "_4" << " " << x << endl;
    }
    
    void _5(int a, int b) {
      cout << "_5" << " " << a << " " << b << endl;
    }
    
    void _6(char a, int b) {
      cout << "_6" << " " << a << " " << b << endl;
    }
    
    void _7(int a, int b, int c) {
      cout << "_7" << " " << a << " " << b << " " << c << endl;
    }
    
    int main() {
      MultiFuncObject funcs;
      funcs += &_1;
      funcs += &_2;
      funcs += &_3;
      funcs += &_4;
      funcs += &_5;
      funcs += &_6;
      funcs += &_7;
      funcs();
      funcs('a');
      funcs(56);
      funcs(5.5);
      funcs(2, 5);
      funcs('q', 6);
      funcs(1, 2, 3);
      return 0;
    }
    

    I hope this is close to what you want. Here is the source of MultiFuncObject:

    #include 
    #include 
    #include 
    
    using namespace std;
    
    template 
    class MultiFuncObject {
      unordered_map m_funcs;
    public:
    
      MultiFuncObject operator +=( R (* f)() ) {
        m_funcs[typeid( R() )] = (void (*)()) f;
        return *this;
      }
    
      template 
      MultiFuncObject operator +=( R (* f)(A1) ) {
        m_funcs[typeid( R(A1) )] = (void (*)()) f;
        return *this;
      }
    
      template 
      MultiFuncObject operator +=( R (* f)(A1, A2) ) {
        m_funcs[typeid( R(A1, A2) )] = (void (*)()) f;
        return *this;
      }
    
      template 
      MultiFuncObject operator +=( R (* f)(A1, A2, A3) ) {
        m_funcs[typeid( R(A1, A2, A3) )] = (void (*)()) f;
        return *this;
      }
    
      R operator()() const
      {
        unordered_map::const_iterator it = m_funcs.find(typeid( R() ));
        if (it != m_funcs.end()) {
          R (*f)() = ( R (*)() )(it->second);
          (*f)();
        }
      }
    
      template 
      R operator()(A1 a1) const
      {
        unordered_map::const_iterator it = m_funcs.find(typeid( R(A1) ));
        if (it != m_funcs.end()) {
          R (*f)(A1) = ( R (*)(A1) )(it->second);
          (*f)(a1);
        }
      }
    
      template 
      R operator()(A1 a1, A2 a2) const
      {
        unordered_map::const_iterator it = m_funcs.find(typeid( R(A1, A2) ));
        if (it != m_funcs.end()) {
          R (*f)(A1, A2) = ( R (*)(A1, A2) )(it->second);
          (*f)(a1, a2);
        }
      }
    
      template 
      R operator()(A1 a1, A2 a2, A3 a3) const
      {
        unordered_map::const_iterator it = m_funcs.find(typeid( R(A1, A2, A3) ));
        if (it != m_funcs.end()) {
          R (*f)(A1, A2, A3) = ( R (*)(A1, A2, A3) )(it->second);
          (*f)(a1, a2, a3);
        }
      }
    
    };
    

    It stores different function prototypes using std::unordered_map with keys of std::type_index and values of void (*)(). When needed, the correct function is retrieved using that map.

    Here is the working example

提交回复
热议问题