Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create an array of function pointers of different prototypes?

I have a few functions defined like this:

ParentClass*    fun1();
ParentClass*    fun2();
ParentClass*    fun3(bool inp=false);
ChildClass*     fun4();
ChildClass*     fun5(int a=1, int b=3);

I would like to put them into an array of some kind as follows:

void* (*arr[5])() = {
    (void* (*)())fun1,
    (void* (*)())fun2,
    (void* (*)())fun3,
    (void* (*)())fun4,
    (void* (*)())fun5
}

Now I would like to use this array of functions simply as

for(int i=0; i<5; i++)
    someFunction(arr[i]());

Now I realize here that the issue is void* (*arr[5])(), but given that I only want to use the functions without supplying an argument, I would like all of these to be part of the same array.

These are very C-style ways to do it, though. Is there a better way to do it using Templates in C++?

like image 485
vc669 Avatar asked Dec 05 '18 09:12

vc669


People also ask

How do you create a function pointer for a function prototype?

The arguments are as follows: pointer to 3 elements integer array, pointer to a function which takes const char pointer as an argument and return type int, array of 3 function pointers and each function takes const char pointer as an argument and return type is int.

How do you declare an array of a function pointer?

int sum(int a, int b); int subtract(int a, int b); int mul(int a, int b); int div(int a, int b); int (*p[4]) (int x, int y); int main(void) { int result; int i, j, op; p[0] = sum; /* address of sum() */ p[1] = subtract; /* address of subtract() */ p[2] = mul; /* address of mul() */ p[3] = div; /* address of div() */ [. ...

What is the prototype of function pointer?

The variable declaration starts with a single return type and ends with the list of parameter types in parentheses. In sum, a function pointer declaration looks exactly like a standard function prototype, with the exception of the (*name) structure where the prototype would just have the function name.

Is array of function pointer possible in C?

In C, we can use function pointers to avoid code redundancy. For example a simple qsort() function can be used to sort arrays in ascending order or descending or by any other order in case of array of structures. Not only this, with function pointers and void pointers, it is possible to use qsort for any data type.

What are the functions of pointers in an array?

Function Pointers as Arguments 1 void *base : void pointer to the array. 2 size_t num : The array element number. 3 size_t width The element size. 4 int (*compare (const void *, const void *) : function pointer composed of two arguments and returns 0 when the arguments have the same value, <0 when arg1 comes before ...

How to declare array of pointers in C++?

How To Declare Array of Pointers in C++? You can declare an array of function pointers in C++ using std::vector<std::function<>> notation, where you should also specify the template parameters for the std::function as needed.

How do you call a pointer function with 3 arguments?

Rather than the standard function calling by taping the function name with arguments, we call only the pointer function by passing the number 3 as arguments, and that's it! Keep in mind that the function name points to the beginning address of the executable code like an array name which points to its first element.

What is the use of pointers in C?

Pointers give greatly possibilities to ‘C’ functions which we are limited to return one value. With pointer parameters, our functions now can process actual data rather than a copy of data. In order to modify the actual values of variables, the calling statement passes addresses to pointer parameters in a function.


3 Answers

C-style or not, what you have is straight undefined behaviour. Use lambdas:

void (*arr[5])() = {
    [] { fun1(); },
    [] { fun2(); },
    [] { fun3(); },
    [] { fun4(); },
    [] { fun5(); }
};

These are okay because they perform the call through the function's correct type, and are themselves convertible to void (*)().

Forwarding the returned value stays simple enough, since the lambda provides a context for the conversion. In your case, since ChildClass supposedly inherits from ParentClass, an implicit conversion is enough:

ParentClass *(*arr[5])() = {
    []() -> ParentClass * { return fun1(); },
    []() -> ParentClass * { return fun2(); },
    []() -> ParentClass * { return fun3(); },
    []() -> ParentClass * { return fun4(); },
    []() -> ParentClass * { return fun5(); }
};
like image 163
Quentin Avatar answered Oct 19 '22 00:10

Quentin


but given that I only want to use the functions without supplying an argument

It simply doesn't work like that. Did you ever wonder, then when you're putting function declarations in a header, why you have to write default parameters into the header and cannot place it in the definition in the implementation source file?

That's because the default parameters are in fact not "embedded" into the function, but used by the compiler to augment a function call with those parameters at a calling location, where those parameters are omitted. (EDIT: Also, as @Aconcagua so keenly observed in a comment, since default parameters are usually defined as part of a header function declaration, any change of the default values requires a full recompilation of any compilation unit that included those headers, ergo function declarations, for the change to actually take effect!)

While it's perfectly possible to do some really weird type casting madness to construct an array of function pointers like that, eventually you'll have to cast back to the original function call signature in order to not invoke undefined behavior.

If anything you'll have to bind the function pointer, together with a set of default parameters in some type that abstracts away the calling, does supply the parameters, and to the outside offers a polymorphic interface. So you'd have a std::vector<function_binder> or function_binder[] where function binder has an operator() that calls the function.

But when you're doing binding in the first place, you can bind it in an anonymous function, i.e. lambdas. At the time of lambda instantiation the default parameters are bound.

std::vector<void(*)()> fvec = {
    []{ func0(); },
    []{ func1(); },
    []{ func2(); }
};
like image 16
datenwolf Avatar answered Oct 19 '22 01:10

datenwolf


You can use std::bind

std::function<ParentClass *(void)> arr[5] = {
    std::bind(&fun1),
    std::bind(&fun2),
    std::bind(&fun3, false),
    std::bind(&fun4),
    std::bind(&fun5, 1, 3)
};

now you can do

for(int i=0; i<5; i++)
    arr[i]();

You have to make sure every function parameter of all functions are bound.

This also works well with member functions. You just have to bind the object reference (e.g. this) as first parameter.

like image 10
Detonar Avatar answered Oct 19 '22 00:10

Detonar