2

I have a class

class A{
    A(/*constructor arguments*/);
    double MethA(double);
};

And I want to pass the method MethA in a function that takes a pointer to a function :

double function(double (*f)(double), double x){
    return f(x);
}

So what I'm doing is to call

A a(/*constructor arguments*/);
function(a.MethA,1.0);

but it doesn't compile.

I'm pretty sure that this question is answered somewhere else, but I couldn't find where because I'm not sure that the terminology I use is correct. Am I trying to pass a pointer on a class method as a function argument ? Or, to pass a function pointer as a member of a class... I'm confused :-(

Casey
  • 41,449
  • 7
  • 95
  • 125
PinkFloyd
  • 2,103
  • 4
  • 28
  • 47
  • 1
    Please spell correctly. `class` is lower-case, and you need a semicolon at the end. Details, but programming is all about details. – Kerrek SB Dec 23 '13 at 14:06
  • Why write code at best is incomprehensible? You got virtual functions. Pass in an object that has one of those and make the code readable – Ed Heal Dec 23 '13 at 14:07
  • a pointer to a member function has a different type than a function pointer – Tim Seguine Dec 23 '13 at 14:11
  • @Tim, this is why i guess I'm lost... I don't understand exactly what type I need to pass in order to call `MethA` within `function` – PinkFloyd Dec 23 '13 at 14:13
  • Is the function you are passing it to one that you wrote? If not, then you need a wrapper function. – Tim Seguine Dec 23 '13 at 14:15
  • @Tim I'm not sure i understand your question, I wrote everything that is contained in the class A and function – PinkFloyd Dec 23 '13 at 14:17
  • Do you have(and are you allowed to use) a C++11 compiler? There is an easier way to do what I think you want to do without mucking about with member function pointers. Member function pointers probably won't do exactly what you want anyway. – Tim Seguine Dec 23 '13 at 14:21
  • @Tim I will run the code on different clusters, some have C++11, some don't. In any case, I'm curious to know the simpler solution... – PinkFloyd Dec 23 '13 at 14:25
  • It's cumbersome but doable without lambdas. You pass your parameter as a function object. You can use templates to avoid spelling out the type. The extra baggage gets optimized away by the compiler. Shall I post an answer? – Tim Seguine Dec 23 '13 at 14:27
  • @Tim, If you don't mind... It will help me a lot ! Thank you! – PinkFloyd Dec 23 '13 at 14:28

3 Answers3

2

When you need to use a pointer to member function, you need to pass two separate things:

  • what member function to call and
  • what instance to call it on.

In C++, you can't combine them in one construct, like you want to:

A a;
bar(a.foo);

is not valid C++.

Instead, you have to do this:

A a;
bar(a, &A::foo)

And declare and implement bar() accordingly:

void bar(A &a, void (A::*method)()) {
    a.*method();
}
1

See Arkadiy's answer if you want to see how to properly use member function pointers.

BUT

As requested in the comments: if the compiler you are using supports lambdas (some without full C++11 do). You can do something like the following, which looks more like the syntax you are attempting to use.

Your definition for function changes to something like:

template <typename F>
double function(F f, double x){
    return f(x);
};

a function template that accepts a parameter that is callable with a double.

At your call-site you do this:

A a(/*constructor arguments*/);
function([&](double x){return a.MethA(x);},1.0);

That generates a function object in-place that is bound to your class instance a by reference.

The template can be made fully typesafe with some magic in <type_traits>, but as-is it will give you template spew if you pass something very wrong.

Community
  • 1
  • 1
Tim Seguine
  • 2,887
  • 25
  • 38
0

It has to be a static function!

#include <iostream>
#include <cassert>
class A {
public:
  static double MethA(double x) { return 5 * x; }
};
typedef double (*ftype)(double);
double function(ftype f) {
  assert(f != NULL);
  return f(7);
}
int main(int, char**) {
  // expect "35\n" on stdout
  std::cout << function(A::MethA) << "\n";
}

It has to be static because you can't access any of A's variables without knowing which A object are you refering to! If you need A's non-static member variables, you need to pass a reference to an a into the static function:

#include <iostream>
#include <cassert>
class A {
  double fX;
public:
  A(double x) : fX(x) { }
  double methB(double x) const { return fX * x; }
  static double MethB(double x, const A& a) {
    return a.methB(x);
  }
};
typedef double (*ftype2)(double, const A&);
double function_with_context(ftype2 f, const A& a) {
  assert(f != NULL);
  return f(7, a);
}

int main(int, char**) {
  A a(6);
  // expect "42\n" on stdout
  std::cout << function_with_context(A::MethB, a) << "\n";
}

But it's sometimes better to use inheritance and polymorphism to achieve this sort of interface:

#include <iostream>
class MyInterface {
public:
  virtual double f(double x) const = 0;
};

class A : public MyInterface {
  double fX;
public:
  A(double x) : fX(x) { }
  double f(double x) const {
    return fX * x;
  }
};

double function(const MyInterface& o) {
  return o.f(7);
}

int main(int, char**) {
  A a(6);
  // expect "42\n" on stdout
  std::cout << function(a) << "\n";
}
Hal Canary
  • 2,154
  • 17
  • 17
  • okay, this solutions works for me... but i don't understand the effect of declaring the method as static. Is it good programing? Will it work if my class is a class template? – PinkFloyd Dec 23 '13 at 14:23
  • It means you can't access any of A's variables. After all, which A object are you refering to? – Hal Canary Dec 23 '13 at 14:24