Link to home
Start Free TrialLog in
Avatar of forums_mp
forums_mp

asked on

implementation approach - part II


I'm at my wits end with in terms of a solution for an implementation approach.  So I garnered assistance here on the creation of a static member function that'll call non-static members
Now I opt to port my example using the VxWorks facility taskSpawn (for more information on taskSpawn see below).  

#include <iostream>

class TEST
{
private:
      int spawned;
                int t_ida;
                int t_idb;
                int t_idc;

      static int bogus;

public:
      typedef void (TEST::*PTRFUNC )();

      TEST() : spawned(0)
      {  
            std::cout <<  " Constructor called " << std::endl;
                                // call function A
                                int t_ida = taskSpawn( "TaskMain", 100, 0, 10000,
                                                                   (FUNCPTR)TEST::TaskMain,(int)this,
                                                                   (int)&TEST::StartA,0,0,0,0,0,0,0,0);

                                // call function B
                                int t_idb = taskSpawn( "TaskMain", 90, 0, 10000,
                                                                    (FUNCPTR)TEST::TaskMain,(int)this,
                                                                   (int)&TEST::StartB,0,0,0,0,0,0,0,0);

                                // call function C
                                int t_idc = taskSpawn( "TaskMain", 80, 0, 10000,
                                                                     (FUNCPTR)TEST::TaskMain,(int)this,
                                                                   (int)&TEST::StartC,0,0,0,0,0,0,0,0);

            //TEST::TaskMain(this, &TEST::StartA);
            //TEST::TaskMain(this, &TEST::StartB);
            //TEST::TaskMain(this, &TEST::StartC);

      }
      ~TEST() { std::cout <<  " Destructor called " << std::endl; }

      static int TaskMain(TEST* obj, PTRFUNC p)
      {
            (obj->*p)();             
            return 0;
      }
      void StartA() { std::cout <<  " A Started " << std::endl; }
      void StartB() { std::cout <<  " B Started " << std::endl; }
      void StartC() { std::cout <<  " C Started " << std::endl; }
};


int main ()
{
      TEST *ptr = new TEST;
      delete ptr;
}

A quick synopsis on taskSpawn. ' (FUNCPTR)TEST::TaskMain'  referenced as a pass parameter to taskSpawn defines the entry point to your function.  In other words, the static function TaskMain inside the class gets called with the passed parameters being the this ((int) this)pointer and the functoin name ((int )&TEST::StartA(B)(C))).

Gcc complains that about the parameter (int) &TEST::StartA and it's ilks StartB and StartC claiming.  "aggregate value used where in integer was expected".   Now I'm unsure what approach to use.  Of course I'm not sure what the ramifications are of using a member function as a passed parameter since taskSpawn expects a 32 bit integer.  I also believe to pass the address of a member function the member function has to be static.

Info on taskSpawn

int taskSpawn
    (
    char *  name,      /* name of new task (stored at pStackBase) */
    int     priority,  /* priority of new task */
    int     options,   /* task option word */
    int     stackSize, /* size (bytes) of stack needed plus name */
    FUNCPTR entryPt,   /* entry point of new task */
    int     arg1,      /* 1st of 10 req'd task args to pass to func */
    int     arg2,
    int     arg3,
    int     arg4,
    int     arg5,
    int     arg6,
    int     arg7,
    int     arg8,
    int     arg9,
    int     arg10
    )

One thought was to change TaskMain to take int arguments then reintrepret cast

      static int TaskMain(TEST* obj, int p)   //perhaps int* p
      {
                               // now reintrepret_cast p back to the PTRFUNC . how?

            //(obj->*p)();             
            return 0;
      }

Could really use some guidance.  Thanks in advance
Avatar of jkr
jkr
Flag of Germany image

>>// now reintrepret_cast p back to the PTRFUNC . how?

static int TaskMain(TEST* obj, int func)  {

   PTRFUNC p = reinterpret_cast<PTRFUNC>( func);
}

should actually do it...

Avatar of forums_mp
forums_mp

ASKER


I'm afraid it didnt.  Same issue "aggregate value used where in integer was expected".

taskSpawn is not liking "(int)&TEST::StartA"

                                int t_ida = taskSpawn( "TaskMain", 100, 0, 10000,
                                                                   (FUNCPTR)TEST::TaskMain,(int)this,
                                                                   (int)&TEST::StartA,0,0,0,0,0,0,0,0);
I don't think you can convert a pointer to a member function to an integer.  I think you will have to change your design.

--efn
SOLUTION
Avatar of jkr
jkr
Flag of Germany 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

With jkr's approach the complaint is

tp.p = &TEST::StartA;   <-----  non-lvalue is assignment

with efn's approach the complaint is

const TEST::PTRFUNC TEST::pA = TEST::StartA; <-----  static member 'int TEST::pA()    
                                                                                     const declared const
&
function 'static int  TEST::pa()' is initialized like a variable

remove the const and static.  so now

PTRFUNC pA, pB, pC;
TEST::PTRFUNC TEST::pA = TEST::StartA

the complaint becomes.  aggregate value used where integer was expected

Bummer i think it's time to just pass an int and just swith on it or design change 2??

------------------------
One other thing

In order for me to get visibility into c++ functions I have to:

1.  declare a static method
   TEST test;

Then wrap them in
 
extern "C" {
   void test_StartA()   // at console type C version and it'll call C++ source
   {
      test.Starta();
   }
}

What this means is i have to have an extern C for StartB and StartC.
I'd like to automate this such that I'll have a on function that'll perhaps take a string then call the appropriate routine

so now
extern "C" {
   void Which_Function ( pass in string )
  {
       switch ( string )
  }
}
Essentially trying to assosciate the string name with the function name with safety checks on the string

or perhaps take the name of the appropriate c++ function and do the same.  suggestions/code sample

thanks
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

You're absolutely right as far as Visual Studio.  That said I refuse to quit :) and as such tried desperately to figure out what I cannot use a static member funciton to call non-static members.
The claim in the Vxworks land is to pass the this pointeras an argument  to the static member function.  Great except I'd now like to expand this to pass an additional parameter ie. the adress of the member function(s) cause I've got lots.

Trouble  is if I make the non-static member function static.  No compiler complaints.  Which means StartA, StartB and StartC has to be static.  
This is borderline ridiculous.  

I dont want StartA, StartB and StartC to be static cause i now get into the whole 'static' mess.   I'm not even sure what to do now.

Did you try the & in

const TEST::PTRFUNC TEST::pA = &TEST::StartA;

?  Are you perhaps missing the * in

    typedef void (TEST::*PTRFUNC )();

?

What compiler are you using?  When I worked with VxWorks, I used gcc;  I got code using this technique to compile with gcc.

You could always try posting your current code that follows our advice and see if we can spot some subtle error.

--efn

Partial success with the &.  No compiler complaints ..

Now the static member funciton TaskMain is not happening for me.  I've got a print statement inside of it that should tell me that "i reached' but thus far to no avail.
Some general questions.  Since TaskMain is static and taskSpawn expects a static member function, there's no need to do 'TEST::TaskMain'?  Of course removing 'TEST::"  didn't work

2.     Consider                               (FUNCPTR)TEST::TaskMain,(int)this,
                                                                   (int)&pC,0,0,0,0,0,0,0,0);
what C++ stlye cast would be good here.   From the looks of my book 'static_cast'

3.  I thought well change to use reinterpret_cast .  So now

((FUNCPTR)TEST::TaskMain,(int)this, reinterpret_cast<int>(&pC),0,0,0,0,0,0,0,0);

now reinterpret_cast back inside TaskMain
static int TaskMain(TEST* obj, int func)  {

   PTRFUNC p = reinterpret_cast<PTRFUNC>( func);   <-- complains
}
complains about 'reinterpret_cast from 'int' to 'void (TEST::*)()'
> Since TaskMain is static and taskSpawn expects a static member function, there's no need to do 'TEST::TaskMain'?

Actually, taskSpawn expects a free function.  It doesn't know anything about members.  You shouldn't need the TEST:: prefix.  All three of the compilers I mentioned above were happy without it.

> 2.     Consider                               (FUNCPTR)TEST::TaskMain,(int)this,
>                                                                    (int)&pC,0,0,0,0,0,0,0,0);
> what C++ stlye cast would be good here.   From the looks of my book 'static_cast'

I think it will have to be reinterpret_cast.

> complains about 'reinterpret_cast from 'int' to 'void (TEST::*)()'

Recall that pC is a PTRFUNC and you couldn't pass it as a fake int parameter, so you passed its address (&pC).  Therefore, you shouldn't be casting func to PTRFUNC, but to pointer to PTRFUNC.

--efn

Many thanks to you two.  Just three questions.
Could you elaborate on the item in brackets with a sample
>> Therefore, you shouldn't be casting func to PTRFUNC, (but to pointer to PTRFUNC)

Just so I understand my book.  Only static const integral types can be initialized insde the class.  All others must pollute the global namespace.

Thats said this would not work inside the class. ths compiler sure did complain :)

const TEST::PTRFUNC TEST::pA = &TEST::StartA;
-----------
This begs another question on initilization

if I have a struct inside a class
class  FOO
{
  struct { int x; int y; };
 
public
   FOO ();
};

The best way to inititialzie to say 5(x) and 1 (y) this in a class world would be ?

 
> Could you elaborate on the item in brackets with a sample
> >> Therefore, you shouldn't be casting func to PTRFUNC, (but to pointer to PTRFUNC)

PTRFUNC* p = reinterpret_cast<PTRFUNC*>( func);
(obj->*(*p))();

> Just so I understand my book.  Only static const integral types can be initialized insde the class.  All others must pollute the global namespace.

A const static member of an enumeration type can also be initialized inside the class, according to the standard.  But some non-conforming compilers don't allow any static initialization inside the class.

I don't have time to answer your third question right now, but I'll get to it later.

--efn
> The best way to inititialzie to say 5(x) and 1 (y) this in a class world would be ?

First you need to have something to initialize.  You haven't declared a structure member, just a structure type.  Assuming you meant to declare a member, I'd suggest you initialize it by giving the structure a constructor.  If you want to initialize the structure with non-default values, you can make a parameterized constructor that is used in the FOO initialization list.

If this is too obscure, let me know, and I can go into more detail.

--efn


I think i comprehend what you're saying

class FOO
{  
  private
     struct MT
     {
           MT(int value_ = 0, const char* name = "")
          {
                   value = value_;
                   strcpy(name, name_);
         }
        int value;
        char name[21];
    }
    MT  xx[4];

public: // done with setup now initialize
  FOO ()
  {
      xx[0] = MT(1, "hello");
      //etc
};

now for stuff like this

// foo.h
struct GENERIC
{
    unsigned char idx;
    unsigned char jdx;
    unsigned char kdx;
    unsigned char ldx;
}  

struct MSG_STRUCT
{  
    GENERIC  data_header;
    unsigned char msg_payld[512];
}

Just memset MSG_STRUCT in FOOs constructor.

Truly appreaciate your assistance