Solved

implementation approach - part II

Posted on 2003-11-11
15
1,116 Views
Last Modified: 2012-06-27

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
0
Comment
Question by:forums_mp
  • 7
  • 6
  • 2
15 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 9722734
>>// 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...

0
 

Author Comment

by:forums_mp
ID: 9723125

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);
0
 
LVL 15

Expert Comment

by:efn
ID: 9724950
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
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 50 total points
ID: 9725011
>>I think you will have to change your design

Good idea - what about

struct TASK_PARAMETERS {

   TEST::PTRFUNC p;
};

TASK_PARAMETERS tp;

tp.p = &TEST::StartA;

                               int t_ida = taskSpawn( "TaskMain", 100, 0, 10000,
                                                                  (FUNCPTR)TEST::TaskMain,(int)this,
                                                                  (int)&tp,0,0,0,0,0,0,0,0);

?
0
 
LVL 15

Accepted Solution

by:
efn earned 200 total points
ID: 9725631
That will work, but I think it could be simpler.  You don't need the structure--you can just take the address of a PTRFUNC.  And you will need a separate one to start each function.  Incomplete example:

class TEST
{
private:
     typedef void (TEST::*PTRFUNC )();
     static const PTRFUNC pA, pB, pC;
public:

     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)&pA,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)&pB,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)&pC,0,0,0,0,0,0,0,0);
     }

     static int TaskMain(TEST* obj, PTRFUNC* p)
     {
          (obj->*(*p))();          
          return 0;
     }
};

const TEST::PTRFUNC TEST::pA = TEST::StartA;
const TEST::PTRFUNC TEST::pB = TEST::StartB;
const TEST::PTRFUNC TEST::pC = TEST::StartC;

It's debatable whether this magic is an improvement over just passing an int code and switching on it.

--efn
0
 

Author Comment

by:forums_mp
ID: 9731476

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
0
 
LVL 15

Assisted Solution

by:efn
efn earned 200 total points
ID: 9733312
Code like that I posted compiled with Microsoft Visual C++ 6.0 and Borland C++Builder 4.  gcc 3.2 wanted an address operator:

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

You could try that.  It seems like your compiler thinks PTRFUNC is a function, not a pointer to a function.

jkr's approach should work too.  Where did you locate the definition of tp?

You can't switch on a string.  If there are not too many possibilities, you could have a series of if-else comparisons.  Or you could use a map where you look up a string and get an int on which you can switch.  Or you could be more wizardly and use a map from string to member function pointer.  Your compiler is giving you so much grief with member function pointers that I hesitate to recommend that, though.

--efn
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 

Author Comment

by:forums_mp
ID: 9734766

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.

0
 
LVL 15

Expert Comment

by:efn
ID: 9735008
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
0
 

Author Comment

by:forums_mp
ID: 9735386

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::*)()'
0
 
LVL 15

Expert Comment

by:efn
ID: 9736468
> 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
0
 

Author Comment

by:forums_mp
ID: 9739975

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 ?

 
0
 
LVL 15

Expert Comment

by:efn
ID: 9741727
> 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
0
 
LVL 15

Expert Comment

by:efn
ID: 9742992
> 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

0
 

Author Comment

by:forums_mp
ID: 9743478

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
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now