Unimportant
Unimportant

Reputation: 2096

Calling another class's member function that is given as template parameter

Impression of what I'm trying to achieve:

class Foo
{
    void func1(int parameter);

    Bar<func1>  bar1;

    void some_member(int parameter)
    {
        bar1(parameter);  //should call func1 trough template function object bar1.
    }
};

Is this even possible? If so, I'd like to see a example implementation of Bar.

As for the why; I have a lot of these member functions like func1, all with the same signature. When the parameter to be passed is 0, the previous non-0 parameter should be used. I'd like to automate this, the function object could remember the parameter and make the 0-check.

Upvotes: 0

Views: 55

Answers (2)

Sam Daniel
Sam Daniel

Reputation: 1902

I think you want to have small helper which will check and act based on your previous parameter.

Below is just an idea, you probably need to extend it.. Since you cannot restore a value to zero in this case.

struct sample
{
   void func1(int data)
   {
      std::cout << "Func 1 , data = " << data << std::endl;
   }
   void func2(int data)
   {
      std::cout << "Func 2 , data = " << data << std::endl;
   }
};


void invoker(std::function<void(int)> call, int param)
{
   static int _param;

   if (param) _param = param;

   call(_param);
}

int main()
{

   sample s;

   using namespace std::placeholders;
   invoker(std::bind(&sample::func1, &s, _1),1);
   invoker(std::bind(&sample::func2, &s, _1),0);

}

Upvotes: 1

Remy Lebeau
Remy Lebeau

Reputation: 598011

To call different methods of a class using a pointer, it would look like this:

class Foo
{
    void (Foo::*bar1)(int);

    void func1(int parameter);
    void func2(int parameter);
    void func3(int parameter);
    ...

    Foo()
    {
        if (condition)
            bar1 = &Foo::func1;
        else if (condition)
            bar1 = &Foo::func2;
        else if (condition)
            bar1 = &Foo::func3;
        ...
    }

    void some_member(int parameter)
    {
        (this->*bar1)(parameter);
    }
};

To wrap that inside a template would look something like this (you can't pass the actual method function pointer as a template parameter, since it is not a constant value at compile-time):

template<typename T>
struct Bar
{
    typedef void (T::*MethodType)(int);

    T *m_obj;
    MethodType m_method;

    Bar(T *obj)
        : m_obj(obj), m_meth(0)
    {
    }

    Bar& operator=(MethodType rhs)
    {
        m_method = rhs;
        return *this;
    }

    void operator()(int parameter)
    {
        if ((m_obj) && (m_method))
            (m_obj->*m_method)(parameter);
    }
}

class Foo
{
    Bar<Foo> bar1;

    void func1(int parameter);
    void func2(int parameter);
    void func3(int parameter);
    ...

    Foo()
        : bar1(this)
    {
        if (condition)
            bar1 = &Foo::func1;
        else if (condition)
            bar1 = &Foo::func2;
        else if (condition)
            bar1 = &Foo::func3;
        ...
    }

    void some_member(int parameter)
    {
        bar1(parameter);
    }
};

Alternatively, if you want the caller to specify the method type:

template<typename T, typename MethodType>
struct Bar
{
    T *m_obj;
    MethodType m_method;

    Bar(T *obj)
        : m_obj(obj), m_meth(0)
    {
    }

    Bar& operator=(MethodType rhs)
    {
        m_method = rhs;
        return *this;
    }

    void operator()(int parameter)
    {
        if ((m_obj) && (m_method))
            (m_obj->*m_method)(parameter);
    }
}

class Foo
{
    Bar<Foo, void (Foo::*)(int)> bar1;
    // or:
    // Bar<Foo, decltype(Foo::func1)> bar1;

    void func1(int parameter);
    void func2(int parameter);
    void func3(int parameter);
    ...

    Foo()
        : bar1(this)
    {
        if (condition)
            bar1 = &Foo::func1;
        else if (condition)
            bar1 = &Foo::func2;
        else if (condition)
            bar1 = &Foo::func3;
        ...
    }

    void some_member(int parameter)
    {
        bar1(parameter);
    }
};

That being said, in C++11 and later, consider using std::bind() and std::function instead of a manual template, eg:

#include <functional>

using std::placeholders::_1;

class Foo
{
    std::function<void(int)> bar1;

    void func1(int parameter);
    void func2(int parameter);
    void func3(int parameter);
    ...

    Foo()
    {
        if (condition)
            bar1 = std::bind(&Foo::func1, this, _1);
        else if (condition)
            bar1 = std::bind(&Foo::func2, this, _1);
        else if (condition)
            bar1 = std::bind(&Foo::func3, this, _1);
        ...
    }

    void some_member(int parameter)
    {
        bar1(parameter);
    }
};

Upvotes: 1

Related Questions