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.)
deleydSoftware EngineerAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jkrCommented:
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?
0
sarabandeCommented:
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
0
deleydSoftware EngineerAuthor Commented:
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.)
0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

sarabandeCommented:
both Action and ActionParam should be class members (or baseclass pointers to class members). then the Execute function could use them using virtual calls.

Sara
0
evilrixSenior Software Engineer (Avast)Commented:
No need to jump through such hoops. The C++11 standard has you covered.

#include <functional>
#include <string>
#include <iostream>

class MyState {};

class MyStateA : MyState
{
   public:
      MyStateA(std::function<void()> func)
         : func_(func)
      {
      }

      void execute()
      {
         func_();
      }

   private:
      std::function<void()> func_;
};

struct MyStateB : MyState{};

void changeStateTo(MyState const & /* state */)
{
   std::cout << "changeStateTo" << std::endl;
}

float DoStuff(int)
{
   std::cout << "DoStuff" << std::endl;
   return 0.0f;
}

void foobar(int, std::string, float)
{
   std::cout << "foobar" << std::endl;
}

int main()
{
   MyStateA a1(std::bind(changeStateTo, MyStateB()));
   a1.execute();

   MyStateA a2(std::bind(foobar, 12, "a string", DoStuff(5)));
   a2.execute();
}

Open in new window


Of course, you'll need to be using a C++11 compliant compiler but both the latest version of gcc and Visual Studio (2013 and 2012 [sort of]) are.

It's also possible to do something similar in C++03 but you'll need to write extra boilerplate code. I can show you how to do that if necessary. Alternatively, you could use Boost, which provides the function<> and bind<> tools.

http://www.cplusplus.com/reference/functional/bind/
http://en.cppreference.com/w/cpp/utility/functional/bind

http://www.cplusplus.com/reference/functional/function/?kw=function
http://en.cppreference.com/w/cpp/utility/functional/function

http://www.boost.org/
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
evilrixSenior Software Engineer (Avast)Commented:
>> 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

0
deleydSoftware EngineerAuthor Commented:
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)
0
evilrixSenior Software Engineer (Avast)Commented:
>> 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? :)
0
evilrixSenior Software Engineer (Avast)Commented:
>> 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
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.