Link to home
Start Free TrialLog in
Avatar of deleyd
deleydFlag for United States of America

asked on

C++ syntax passing function as parameter

(My knowledge is more C# and less C++, so C++ syntax I'm not as familiar with.)

I want to create a class, and I want to pass to the constructor a function, and this function has a class type as a parameter. It's also possible I might want to pass a completely different function, with completely different parameters.

Either way I want the function parameters defined when I create the class.

Perhaps an example would better demonstrate. I'll start with a class definition for a class named MyStateA, this class will have a method named Execute, so if I instantiate an instance of class MyStateA, something like
a = new MyStateA
a.Execute()

Open in new window

(syntax is totally wrong here. I'm not even sure if I use new or I think there's a variation of new that I should use instead.)

Now say I want to instantiate an instance of class MyStateA, and I want a.Execute() to run ChangeStateTo(MyStateB).

So when I instantiate my instance of class MyStateA, I pass as a parameter ChangeStateTo(MyStateB). Something like:
a = new MyStateA( ChangeStateTo(MyStateB) )

Open in new window

The desired end result is when I call
a.Execute()

Open in new window

it will run ChangeStateTo(MyStateB)

Then method ChangeStateTo can instantiate an instance of MyStateB.

I just need to get the C+++ syntax right for this.

Notice I'm not passing parameters to a.Execute(), I want a.Execute() to run ChangeStateTo(MyStateB). Or, alternately, I might want a.Execute() to run foobar( 12, "a string", DoStuff(5) )

If the resulting C++ code for this dynamic approach is too convoluted I could fall back to using static classes. The program will have a finite number of classes that can be created. I thought maybe I could save memory space if I dynamically created the classes as I needed them and destroyed them when I was done with them. However, I don't know if behind the scenes that might end up with a lot of memory fragmentation, so perhaps I should just statically create all my classes once and be done with it, especially if it makes the resulting code a lot simpler.

In which case, what would be the C++ syntax for doing the above assuming all the classes are static? That is, just one instance of each class. (I don't think I need to use the Singleton Design Pattern do I? Can't I just declare a class static and start using it?)

A full example would be nice since I'm not as familiar with C++ syntax. (This will be unmanaged C++, not .NET C++. I think the target compiler is a variation of the GNU C++ compiler.)
Avatar of jkr
jkr
Flag of Germany image

Wait a minute - you want to pass the constructor a type, not the instance of an object? I what you want to do somehow in the direction of templates?
I want a.Execute() to run ChangeStateTo(MyStateB). Or, alternately, I might want a.Execute() to run foobar( 12, "a string", DoStuff(5) )

the 1st problem with your requirement is that both functions have arguments which you don't supply when you call a.Execute(). 2nd issue is that ChangeStateTo and foobar have different number of arguments and different argument types. because of both the requirements cannot be solved by a function pointer stored as member:

typedef void (*MyFunc)(MyStateB * msb);
class MyStateA
{
      MyFunc func;
      ...
public:
      MyStateA(MyFunc f) : func(f) { }
      Execute() { if (func != NULL) func(new MyStateB()); }
      ....

Open in new window


the sample solves the first issue by creating a new pointer in Execute but obviously the foobar function could not be passed because it doesn't fit to the MyFunc prototype.

to solve both parts of the requirements, you better would pass a baseclass pointer of a kind of argument class to the constructor of your class:

// forward declaration
class A;

class B
{
public:
     virtual void Execute(A * pa) = 0;
};

class D : public B
{
     MyStateB msb;
public:
     D(int x) : msb(x) { }
     void Execute(A* pa) { ChangeToState(pa, &msb); }
     ...

class A
{
    B * pb;
public:
    A(Base * p) : pb(p) {}
    void Execute() { pb->Execute(this); }
    ....

int main()
{
     D d(123);
     A a(&d);
     a.Execute();  // would call d.Execute() via B pointer
     ....

Open in new window


with the above, the final function called would have access to A instance and to D instance which can have arbitrary members (properties). so, if you need other arguments you would derive a new class from B and implement appropriate data members and execute function.

Sara
Avatar of deleyd

ASKER

How about something like this.
I'm having trouble with lines 5,9,10:
  list<MenuItem> menuItems;

  MenuItem menuItemA;
  menuItemA.MenuText = "Hello World from menuItemA";
  menuItemA.Action = MyMethod(my parameters);
  
  menuItems.push_back(menuItemA);

  cout << menuItemA.MenuText;
  menuItemA.Execute(); //runs Action. Calls MyMethod(my parameters)

Open in new window

MenuItem.h
Here I don't know what to put for line 7, or how to define the Execute function so it runs the Action.
class MenuItem
{
public:
  MenuItem(void);
  ~MenuItem(void);
  string MenuText;
  Action ???
  void Execute() {
     ???
  }
};

Open in new window

Also what's the trick so the cout will work with a string? (Or maybe there's something else besides cout I can use, since this is just for testing purposes.)
SOLUTION
Avatar of sarabande
sarabande
Flag of Luxembourg image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>> what's the trick so the cout will work with a string?

#include <string>
#include <iostream>
std::string s = "hello world";
std::cout << s << std::endl;

Open in new window

Avatar of deleyd

ASKER

Excellent using std::bind to fill in the parameters.

My only problem is our target compiler currently doesn't support std::bind. Is there an alternative?

Or I'll code using std::bind and hope our compiler vendor updates their compiler by the time we're done.

(Using Red Suite 5)
>> Is there an alternative?
Yeah... use the Boost version.
http://www.boost.org/doc/libs/1_54_0/libs/bind/bind.html

It's a header only module so you could use it without introducing a dependency on the whole of Boost.

Alternatively, you can just create your own function objects by hand by overriding the class function operator.

*** warning, this code is untested - it's just an example I typed directly into the browser.

// basically, bind just automates the creation of an object like this
class func_wrapper
{
   public:
      func(function<void()> func, int p1, float p2)
         : func,  {}
         , p1_(p1)
         , p2_(p2)

      void operator()() const
      {
          func_(p1, p2);
      }

   private:
      function<void()> func_;
      MyStateB myStateB_;
      float p2_;
};

void func_to_call(int, std::string const & s, float)
{
}

MyStateA a1(func_wrapper(func_to_call, 12, "hello", 56.234));
a1.execute();

Open in new window


>>  hope our compiler vendor updates their compiler by the time
Which compiler are you using? All the main stream compilers now support C++11 but on some you have to enable it. For example, with gcc (and, I think this also applies to clang) you have to provide it the following flag:

-std=c++11

Visual Studio 2013 just works (mostly).

If you are using another compiler and it doesn't yet support the C++11 standard you should give your vendor some serious grief. It's been 2 years since the standard was ratified and before then the TR1 (the Technical Report that formed the basis of the standard) was in draft for about 3 years. There really is no excuse for compiler vendors not supporting the current C++ standard. Can you tell I'm very grumpy about this subject? :)
>> Using Red Suite 5
Oops... just noticed that (sorry, missed it initially). I have no experience with this product I'm afraid but they claim to use "Industry standard GNU toolchain", which would suggest to me it is based on gcc. It also looks like their product is being end-of-life'd due to 3rd party aquisition!

http://www.support.code-red-tech.com/CodeRedWiki/RedSuiteFuture