Home > Software design >  About std::function usage and if-else problem
About std::function usage and if-else problem

Time:12-25

as the below code, I don't want so many "if else"

class A
{
public:
    void f0()
    {
        cout << "f0" << endl;
    }
    void f1()
    {
        cout << "f1" << endl;
    }
    void f2()
    {   
        cout << "f2" << endl;
    }
    //..... more functions fn()...
};


class B
{
public:
    void f(int n)
    {
        //vector< function<void()> > f_v {obj_a.f0, obj_a.f1, obj_a.f2}; //this usage is not correct
        if (n == 0)
            obj_a.f0();
        else if (n == 1)
            obj_a.f1();
        else if (n == 2)
            obj_a.f2();
        //.....more else if here
    }
private:
    A obj_a;
};

I want to create a vector and use std::function to avoid using so many if-else , like vector< function<void()> > f_v {obj_a.f0, obj_a.f1, obj_a.f2}; but it doesn't work, maybe the usage of std::function is not very correct. How should I do? Or is there any other good way to solve the problem of if else, I think use so many switch-case is also not very elegant :)

update: Some answers have already solve my problem about the usage of std::function in my earlier code;

More generally, considering the below code, if the member functons A::f1(), A::f2().... have different return types, but still have some connection that they derived from a same base class , what's the good way to implement the logic of if else in B::f()?

class Base 
{
public:
    virtual ~Base()=default;

};

class D1 : public Base
{
public:

};

class D2 : public Base
{
public:

};

class D3 : public Base
{
public:

};
// ....maybe more class derived form Base
class A
{
public:
    D1* f0()
    {
        cout << "f0" << endl;
        return &d1;
    }
    D2* f1()
    {
        cout << "f1" << endl;
        return &d2;
    }
    D3* f2()
    {   
        cout << "f2" << endl;
        return &d3;

    }
    //more fn()....

private:
    D1 d1;
    D2 d2;
    D3 d3;
    //.....
};

class B
{
public:
    void f(int n)
    {
        if (n == 0)
            obj_a.f0();
        else if (n == 1)
            obj_a.f1();
        else if (n == 2)
            obj_a.f2();
        //.....more else if here
    }
private:
    A obj_a;
};

CodePudding user response:

You can use std::function with a lambda wrapper,

vector<function<void()>> f_v {[this]() { obj_a.f0(); }, 
                              [this]() { obj_a.f1(); }, 
                              [this]() { obj_a.f2(); }};
f_v[n]();

or use pointer-to-members directly,

vector<void (A::*)()> f_v { &A::f0, &A::f1, &A::f2 };
(obj_a.*f_v[n])();

CodePudding user response:

If you are aiming at speed and you know the number of methods, avoid using std::vector for the extra indirection. Use std::array as it will hit cache with the current object.

For this simple case, you don't necessarily need to use std::function, which is a very heavy object to call. You can use pointers to members like this:

#include <iostream>
#include <array>

using namespace std;

class A
{
public:
    void f0()
    {
        cout << "f0" << endl;
    }
    void f1()
    {
        cout << "f1" << endl;
    }
    void f2()
    {   
        cout << "f2" << endl;
    }
    //..... 
};


class B
{
public:
    B() {
        fn[0] = &A::f0;
        fn[1] = &A::f1;
        fn[2] = &A::f2;
    }
    void f(int n)
    {
        ((obj_a).*(fn[n]))();
    }
private:
    using Fn = void (A::*)();
    std::array<Fn,3> fn;
    A obj_a;
};

Code: https://godbolt.org/z/z4KqKvn99

CodePudding user response:

Your approach seems correct. You just need to std::bind those member functions like

class B{
std::vector <std::function <void()>> m_vec_functs; 
...
B(const A& a)
{
 m_vec_functs.push_back(std::bind(&A::f0, a));
 m_vec_functs.push_back(std::bind(&A::f1, a));
}

void f(unsigned int n)
{
 m_vec_functs[n];
}
...
};

Then you can access each individual function by its index, knowing their order.

  • Related