1

I would like to pass class member functions as a template parameter as shown in below example in main function. Could you please help? It is working fine, if I pass normal functions as input parameters.

template <int n>
class meta
{
public:
  template <typename F1, typename F2>
  void operator()(F1& f1, F2& f2)
  {
     if (f2())
     {
       f1(n);
     }
  }
};

class temp
{
public:
  void func1(int x)
  {
     cout << "inside func1" << endl;
  }

  bool func2()
  {
    cout << "inside func2" << endl;
    return true;
  }
};


int main()
{
  temp t;

  meta<10>()(t.func1, t.func2);  //not working, func1 and func2 are class member functions

//meta<10>()(func1, func2);   //working, if func1 and func2 are normal functions (not part of the class)
}

Dr. Gut
  • 2,053
  • 7
  • 26
coder
  • 123
  • 4
  • "not working" is not a problem description. If you try to compile/run that code, what happens? Why is that bad? Anyway, a member function needs an instance on which to call it, so you need to bind an instance, and you can search and find plenty answers about how to do that. – underscore_d Oct 02 '20 at 16:31
  • 1
    Does this answer your question? [How can I pass a member function where a free function is expected?](https://stackoverflow.com/questions/12662891/how-can-i-pass-a-member-function-where-a-free-function-is-expected) – underscore_d Oct 02 '20 at 16:32
  • My bad! It gives an error saying "error: no match for call to '(temp<10>) (, )' " – coder Oct 02 '20 at 16:34
  • @underscore_d No, the question is the other way round. – πάντα ῥεῖ Oct 02 '20 at 16:50

2 Answers2

4

If you want to pass member functions as arguments, you can pass them as member function pointers, but you need to pass an object of that type to the function as well. (If there's no object, there's no member function to call).

Also, note that the syntax for calling the member function is different as well:

template <typename T>
void operator()(T &t, void (T::*f1)(int), bool (T::*f2)())
{
   if ((t.*f2)())  // call member functions like this
   {
     (t.*f1)(n);
   }
}

and now you can call the function this way:

meta<10>()(t, &temp::func1, &temp::func2); 

Here's a demo.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • [More details on how you can use and avoid abusing member function pointers](https://isocpp.org/wiki/faq/pointers-to-members) – user4581301 Oct 02 '20 at 16:49
  • @coder Glad it helped :) Consider accepting the answer if it answers your question. – cigien Oct 02 '20 at 22:47
0

To call a member function you must have an object on which you call it. Your code does not work, because t is not passed to meta::operator() in any way. To solve the problem we will address this issue.

The syntax in meta::operator() is f1(n) and f2(). Therefore F1 and F2 must be either

  • function types, or
  • class types which have an operator().

To make this work, we will use the latter. In main let's store a pointer to t in an object, and for the class of that object we will make an operator() which will call the method on t. Like this:

struct caller1 {
  void operator()(int x) const { t->func1(x); }
  temp* t;
};

struct caller2 {
  bool operator()() const { return t->func2(); }
  temp* t;
};

int main()
{
  temp t;

  caller1 c1 { &t };
  caller2 c2 { &t };
  meta<10>()(c1, c2);
}

But with the C++ Standard Library it's even simpler. You don't need to create classes like caller1 and caller2. You can use std::bind in header functional (live demo):

int main()
{
  temp t;

  auto f1 = bind(&temp::func1, &t, placeholders::_1);
  auto f2 = bind(&temp::func2, &t);
  meta<10>()(f1, f2);
}

Passing &t to bind creates a class that stores a pointer to t. If for some reason you need to store a copy of t in f1 and f2, pass t to bind.

Dr. Gut
  • 2,053
  • 7
  • 26