3

In some languages (PHP and JavaScript come to mind), I can use a variable as a function. For example:

PHP: Class::$var_function();

Is it possible to this in C++ in a way that doesn't require a switch or if statement?

Calvin Froedge
  • 16,135
  • 16
  • 55
  • 61
  • It must be pointed out that the PHP snippet above is *not using* a variable as a function. It is using a variable to *create an identifier dynamically* (a form of "variable variables") for a method call. In the C/C++ code below, an actual "handle" (function pointer or std::function) to the function is used and the identifiers themselves are stable.comments may only be edited for 5 minutes(click on this box to dismiss) –  Jan 09 '12 at 04:50
  • (In the case of JavaScript, which is very unlike PHP in this aspect, functions are proper first-class values and behave as any other object value: an object is itself.) –  Jan 09 '12 at 04:52

4 Answers4

4

Yes. Such a variable is called a function pointer (for nonmember or static member functions) or a pointer-to-member-function (for nonstatic member functions).

Alternatively, Boost, C++ TR1, and C++11 all provide a polymorphic function wrapper, which is basically an uber-flexible, general purpose, generic function pointer type.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
4

This is what pointers to functions allow you to do.

int max(int v1, int v2) { return (v1 > v2) ? v1 : v2; }
int min(int v1, int v2) { return (v1 < v2) ? v1 : v2; }
int add(int v1, int v2) { return v1 + v2; }
int (*function)(int, int) = add;

int x = function(1, 3);  // x == 4
function = min;
int y = function(1, 3);  // x == 1

Etc.

You can also get pointers to member functions in C++; the notation is somewhat different.

You may see code invoking functions via pointers to functions using the notation:

function = max;
int z = (*function)(1, 3);  // x == 3

This is old fashioned, pre-standard C. But it makes it clear that a pointer-to-function is being used (so I still like it and often use it).

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
4

James' answer is probably the best. But, if you're using a c++11 compatible compiler, you can alternately use std::function

For example:

#include <functional>
#include <iostream>
typedef std::function<void(int a)> callback_t;

class A {
public:
   void fn(int a) { std::cout << a << std::endl; }
};

void fn2(int b) { std::cout << a << std::endl; }

int main() {
   A a;
   callback_t c = std::bind(&A::fn, a, std::placeholders::_1);
   c(1);

   c = fn2;
   c(2);

   return 0;
}

And a boost version (I've never used this so it may be wrong):

#include <boost/function.hpp>
#include <iostream>
typedef boost::function<void(int a)> callback_t;

class A {
public:
   void fn(int a) { std::cout << a << std::endl; }
};

void fn2(int b) { std::cout << a << std::endl; }

int main() {
   A a;
   callback_t c = boost::bind(&A::fn, a, boost::placeholders::_1);
   c(1);

   c = fn2;
   c(2);

   return 0;
}
Naddiseo
  • 1,014
  • 1
  • 7
  • 17
  • I get this compiler error on the typedef declaration: error: expected initializer before ‘<’ token – Calvin Froedge Jan 09 '12 at 04:41
  • What compiler are you using? If it's g++, pass -std=c++0x to it. – Naddiseo Jan 09 '12 at 04:47
  • cc1plus: error: unrecognized command line option "-std=c++0x" Yea, I'm using g++ (Mac OS X) – Calvin Froedge Jan 09 '12 at 04:59
  • You'll need to use a recent-ish version, >4.5 I think. The other alternate is to use boost, that James linked to above. I'll update my post to add a boost version – Naddiseo Jan 09 '12 at 05:01
  • Cool, man. Thanks. I'll check into both after I've had some sleep. I really appreciate the help = ) – Calvin Froedge Jan 09 '12 at 05:06
  • 1
    I'm not sure if this is still an issue, but doesn't `A a();` declare a local function returning a class `A` that takes no arguments? I think you want just `A a;` – dreamlax Jan 09 '12 at 05:28
  • @deramlax: Indeed, fixed. The worse problem is that `a.fn` is illegal. See http://stackoverflow.com/questions/5154116/stdfunction-to-member-function – MSalters Jan 09 '12 at 09:39
0

In addition to the other answers, you can make objects of any user-defined type act like a function (or even like a set of overloaded functions) by defining the function call operator:

class MyClass
{
public:
  MyClass(): member(42) {};
  void operator()(int i) { std::cout << (member=i) << '\n'; }
  void operator()() { std::cout << member++ << '\n'; }
private:
  int member;
};

int main()
{
  MyClass foo;

  foo();   // prints 42
  foo();   // prints 43
  foo(23); // prints 23
  foo();   // prints 24
}
celtschk
  • 19,311
  • 3
  • 39
  • 64