简体   繁体   中英

Callback functions with different arguments

I have two functions with a little different functionality, so I can't make them as template functions.

int func64(__int64 a) {
  return (int) a/2; 
} 
int func32(int a) {
    return a--; 
} 

Depending on variable b64, I would like to call func64 or func32. I don't want check if b64 is true many times in my code, so I use pointers to functions.

void do_func(bool b64) {
    typedef int (*pfunc32)(int);
    typedef int (*pfunc64)(__int64);
    pfunc32 call_func; 
    if (b64) 
        call_func = func64; //error C2440: '=' : cannot convert from 'int (__cdecl *)(__int64)' to 'pfunc32'
    else
        call_func = func32;
    //...
    call_func(6); 
} 

How can I avoid this error and cast call_func to pfunc32 or pfunc64?

Pass a void pointer and cast it in the function body.

Of course this means less compiler control if you use the wrong type; if you call func64 and pass an int to it the program will compile and produce wrong results without giving you any tip of what is going wrong.

int func64(void *a) {
   __int64 b = *((__int64*) a);  
   return (int) b/2; 
} 

int func32(void *a) {
   int b = *((int *) a)
   return b-1; 
} 

The language requires all functions called through the same function pointer to have the same prototype.

Depending on what you want to achieve, you could use the pointer/cast aproach already mentioned (which satisfies this requirement at the loss of type safety) or pass a union instead:

union u32_64
{
    __int64 i64;
    int i32;
};

int func64(union u32_64 a) {
   return (int) a.i64/2;
} 

int func32(union u32_64 a) {
    return --a.i32;
}     

void do_func(bool b64) {
    typedef int (*pfunc)(union u32_64);

    pfunc call_func;   
    if (b64)            
        call_func = func64;
    else                    
        call_func = func32;         
    //...                               

    union u32_64 u = { .i64 = 6 };
    call_func(u);                           

}

Well, first of all, please note that function func32 is returning the input argument as is .

This is because with return a-- , you are returning the value of a before decrementing it.

Perhaps you meant to return a-1 instead?

In any case, you can simply declare this function as int func32(__int64 a) .

This way, it will have the same prototype as function func64 , but will work exactly as before.

BTW, calling a function through a pointer might be more "expensive" than a simple branch operation, so depending on your application, you might be better off with a simple if / else conditional statement...

I need to call func32() or func64() depending on flag b64

So do that:

void do_func(bool b64) {
    if (b64) 
        func64(6);
    else
        func32(6);
} 

Make a wrapper for func64 :

int func64_as_32(int a) {
    return func64(a);
}

Now you can assign either func32 or func64_as_32 to call_func since they have the same signature. The value you pass in, 6 , has type int so passing it to func64_as_32 has the same effect as passing it directly to func64 .

If you have call sites where you pass in a value of type __int64 then you'd do it the other way around, wrap func32 .

As bool in C++ converts to int ( true => 1 , false => 0 ) you can use b64 as array index. So take SJuan76's advice, convert your functions prototype to int f(void*) and put them into array int (*array_fun[2])(void* x); . You can call these functions then like that :

int p = 6; 
array_fun[b64](&p);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM