Search code examples
c++templatespointer-to-member

How to get a C++ template class to invoke another class' methods?


I have class A that needs to invoke the member functions of template class B. Searching around I found this sample code on this site:

#include <iostream>

template<typename T, typename FType>
void bar(T& d, FType f) {
  (d.*f)(); // call member function
}

struct foible
{
  void say()
  {
    std::cout << "foible::say" << std::endl;
  }
};

int main(void)
{
  foible f;
  bar(f,  &foible::say); // types will be deduced automagically...
}

That came from this answer: C++ method name as template parameter

But it doesn't do 100% of what I need. How would the above code be re-written so that:

  1. method bar is a public member of a class and not a stand-alone function
  2. arguments d and f which are getting passed to method bar are public members of the same class to which bar is a member, allowing bar to be of type void (void)
  3. object type foible is a class and not a structure (optional)?

[EDIT 1] My own attempt at the rewrite which meets points 1) and 2) is the following, which is wrong:

#include <iostream>

template<class T, void (T::*FType)()>
class foo {
public:
  T obj;
  FType f;
void bar(void) {
  (obj.*f)(); // call member function
} // end bar
}; // end class foo

struct foible
{
  void say()
{
  std::cout << "foible::say" << std::endl;
}
};

int main(void)
{
foible f;
foo<foible, void (foible::*)()> c;
c.T = f;
c.Ftype = &foible::say;

c.bar(); // types will be deduced automagically...
}

My goal is to have an object of class type 'A' invoke the methods of object of class type 'B', so that when these methods execute the object of type 'B' can use its 'this' pointer to reference its local data. I want to use function pointers inside class type 'A' so that these only need to be specified once, and I don't want one class to have to be derived from another.


Solution

  • A step by step solution: all examples uses the following class and foo function

    #include <iostream>
    class A
    {
    public:
        void foo(){std::cout<<"foo"<<std::endl;}
    };
    

    this sample works without template: just calling the calling A::foo with pointer to A and pointer to A::foo:

    class B
    {
    public:
        A *a;
        void (A::*p)(); 
    
        void bar()
        {
            (a->*p)(); //call A::foo 
        }
    };
    int main(void)
    {
        A a;
        B b;
        b.a = &a;
        b.p = &A::foo;
        b.bar();
        return 0;
    }
    

    The following sample added template class T, the pointer to foo method derived from T.

    template <class T>
    class C
    {
    public:
        T* t;
        void (T::*p)(); 
        C(T &o) : t(&o){} 
        void bar()
        {
            (t->*p)();
        }
    };
    int main(void)
    {
        A a;
        C<A> c(a);
        c.p = &A::foo;
        c.bar();
        return 0;
    }
    

    in the following, the method pointer was templated too, but I don't see how can it be used since you should know how many argument to give it, but anyway:

    template <class T, typename F>
    class D
    {
    public:
        T* t;
        F p; 
        D(T &o, F pf) : t(&o),p(pf){} 
        void bar()
        {
            (t->*p)();
        }
    };
    int main(void)
    {
        A a;
        D<A, void (A::*)()> d(a, &A::foo);
        d.bar();
        return 0;
    }