That was a mouthful. Essentially I have this:
typedef int (*decker_function_t)(int);
decker_function_t decker;
// Some logic making decker point to a real function
int i = decker(5);
return 1;
However, what I really want is for functions of type decker_function_t
to return a type of decker_function_t
, rather than an int
. I cannot figure out how to make a typedef self-referential. Is this possible?
Also please note I am asking strictly for C, not C++,
It is not possible to declare it directly. The language syntax does not offer the opportunity to break the infinite declarative recursion inherently present in this declaration, which is a pity, since there's no physical recursion in it.
The workarounds would include
Using a "generic" function pointer type void (*)(void)
for the return type. Of course, you will have to cast the returned value to the desired specific function type. This is what is usually suggested as "use void *
" solution, except that void *
is not the right way to go about it (formally data pointer types are not interconvertible with function pointer types).
Using a wrapper struct type as a middle-man. The language allows referring to struct type from the declaration of the very same struct type in a number of contexts. In a way, that is a supported form of "infinite declarative recursion". By taking advantage of this one can do
struct fptr_struct {
struct fptr_struct (*fptr)(int);
};
and declare such functions as returning struct fptr_struct
type. This will also require some insignificant syntactic efforts to obtain the returned pointer, i.e. access to the nested fptr
field, but at least it does not require a cast.
Following from the function returning itself SO; its possible to return a dummy function pointer which can then be properly cast.
This avoids using a void * and non-standard casting. So it can't return itself, but is able to return a dummy fp and can be handled by convention:
#include <stdio.h>
typedef int (*dummy_function_type)(int);
typedef dummy_function_type (*decker_function_t)(int);
dummy_function_type some_task(int someparam)
{
/* do some work.. */
fprintf(stdout, "%s\n", __FUNCTION__); //gcc specific
return 0;
}
dummy_function_type decker_queue_root(int redundantparam)
{
/* do some work.. */
fprintf(stdout, "%s\n", __FUNCTION__); //gcc specific
return (dummy_function_type)some_task;
}
void process_decker_queue(decker_function_t jobs)
{
/* nonstandard gcc function nesting follows */
decker_function_t next_decker(decker_function_t cur_decker, int param)
{
if(!cur_decker)return 0;
return (decker_function_t)(cur_decker(param));
}
decker_function_t cursor;
cursor = jobs;
while(cursor)
{
cursor = next_decker(cursor, 0); //param seems pretty redundant in this context..
}
}
int main()
{
//work queue stack
decker_function_t prime = &decker_queue_root;
process_decker_queue(prime);
fprintf(stdout, "this compiles..\n");
return 0;
}
This gives the following output:
$ ./test_frecurse
decker_queue_root
some_task
this compiles..
But it would be simpler to just have a list of jobs and call them in order
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With