#include <functional>

class Button
{
  // Allgemeines Ding, das sich wie eine Funktion verhält, die void zurück gibt und keine Parameter hat:
  std::function<void()> f;

public:
  // Akzeptiert alles, was sich irgendwie void()-artig aufrufen lässt:
  template <typename T> void set_function(T t) { f = t; }

  void invoke_function()
  {
    f();
  }
};


// von hier an dient alles nur der Demonstration:
#include <iostream>
using std::cout;

void void_funktion_ohne_parameter() { cout << "void_funktion_ohne_parameter\n"; }

void void_funktion_mit_parameter(int i) { cout << "void_funktion_mit_parameter: " << i << '\n'; }

struct Foo 
{ 
  void nicht_statische_memberfunktion_ohne_parameter() { cout << "nicht_statische_memberfunktion_ohne_parameter\n"; }
  void nicht_statische_memberfunktion_mit_parameter(int i) { cout << "nicht_statische_memberfunktion_mit_parameter: " << i << '\n'; }
  static void statische_memberfunktion() { cout << "Langweilig!\n"; }
};

struct Functor
{
  void operator()() { cout << "Functor\n"; }
};

int main()
{
  using std::bind;

  Button button;

  button.set_function(void_funktion_ohne_parameter);  // Bei freien Funktionen kann man den Adressoperator auch weglassen
  button.invoke_function();

  button.set_function(bind(void_funktion_mit_parameter, 5));
  button.invoke_function();

  Foo foo;

  button.set_function(bind(&Foo::nicht_statische_memberfunktion_ohne_parameter, &foo));  // Bei Memberfunktionen ist der Adressoperator nötig
  button.invoke_function();

  button.set_function(bind(&Foo::nicht_statische_memberfunktion_mit_parameter, &foo, 5));  
  button.invoke_function();

  button.set_function(Foo::statische_memberfunktion);  // Statische Memberfunktionen sind auch nicht anders als freie Funktionen mit besonderem Namen.
  button.invoke_function();
  
  button.set_function(Functor());  // ALLES was irgendwie wie void() aufrufbar ist funktioniert
  button.invoke_function();

  button.set_function([](){cout<<"Lambda\n";});  // Das ist insbesondere praktisch für Lambdas
  button.invoke_function();
}