Search code examples
c++classvectorfunction-pointersclass-method

list/vector of class methods in a class variable


I need to maintain a list of methods that will be executed in different orders for testing. We are moving away from C to C++ to use google framework. Is it possible to maintain a list of functions pointers to some of the class methods to be used for execution inside the class, so that they can be used after instantiation ? please refer http://cpp.sh/265y

#include <iostream>
#include <string>
#include <vector>
using namespace std;

typedef void (*funcType)();

class Sample {
    public:
    vector<funcType> func_list;

    Sample();

    void formList();
    void method1();
    void method2();
    void method3();    
};

void Sample::formList() {
    func_list.push_back(&method1);
    func_list.push_back(&method2);
    func_list.push_back(&method3);
}

void Sample::method1 () {
    cout << "method1" << endl;
}

void Sample::method2 () {
    cout << "method2" << endl;
}

void Sample::method3 () {
    cout << "method3" << endl;
}

int main()
{
    Sample sample; //* = new Sample();
    sample.formList();
    vector<funcType>::iterator it;
    for (it = sample.func_list.begin(); it != sample.func_list.end(); ++it) {
         ((*it));
    }

}

Answer: http://cpp.sh/8rr2


Solution

  • You could use the dreaded pointer-to-member-function syntax:

    Live On Coliru

    // Example program
    #include <iostream>
    #include <string>
    #include <vector>
    using namespace std;
    
    class Sample;
    
    typedef void (Sample::*funcType)();
    
    class Sample {
      public:
        vector<funcType> func_list;
    
        Sample(){}
    
        void formList();
        void method1();
        void method2();
        void method3();
    };
    
    void Sample::formList() {
        func_list.push_back(&Sample::method1);
        func_list.push_back(&Sample::method2);
        func_list.push_back(&Sample::method3);
    }
    
    void Sample::method1() { cout << "method1" << endl; }
    
    void Sample::method2() { cout << "method2" << endl; }
    
    void Sample::method3() { cout << "method3" << endl; }
    
    int main() {
        Sample sample; //* = new Sample();
        sample.formList();
        vector<funcType>::iterator it;
        for (it = sample.func_list.begin(); it != sample.func_list.end(); ++it) {
            (sample.*(*it))(); // HORRIFIC, INNIT? SEE BELOW FOR BETTER
        }
    }
    

    MUCH BETTER:

    However, you could be much more versatile using C++11/TR1 std::function<> or boost::function<>:

    typedef function<void(Sample*)> funcType;
    
    // ...
    func_list.push_back(mem_fn(&Sample::method1));
    func_list.push_back(mem_fn(&Sample::method2));
    func_list.push_back(mem_fn(&Sample::method3));
    

    See it Live On Coliru too

    for (it = sample.func_list.begin(); it != sample.func_list.end(); ++it) {
        (*it)(&sample); // much better
    }
    

    The added versatility is mainly in that you can cater for different signatures: Live On Coliru

    class Sample {
      public:
        vector<funcType> func_list;
    
        Sample(){}
    
        void formList();
        void method1(int);
        void method2(std::string);
        void method3(double, double, double);
    };
    
    void Sample::formList() {
        using std::placeholders::_1;
        func_list.push_back(bind(&Sample::method1, _1, 42));
        func_list.push_back(bind(&Sample::method2, _1, "Hello world"));
        func_list.push_back(bind(&Sample::method3, _1, 1, 2, 3));
    }