Reputation: 99344
Reading a question in stackoverflow, I wondered whether it's possible to declare a function that takes a pointer to itself. I.e. to make such declaration of foo
, for which the following would be correct:
foo(foo);
The simpliest idea is casting to another function pointer (can't cast to void*
, since it may be smaller), so the function declaration looks like this:
void foo(void (*)());
While that's OK in C (and will work with casting in C++), I wonder, whether it can be done without such hard "reinterpret" casting or losing type information.
In other words, I want the following declaration:
void foo( void (*)( void (*)( void (*) ( ... ))));
but, of course, unlimited declarations are impossible. Naive typedef
ing doesn't help either.
C++ templates are welcome, even if they make the calling code (foo(foo)
) look a bit less succinct, but still finite.
C-style answers that show, how one can drop type information without casting, or other tricks of that sort are, of course, interesting, but won't be accepted.
Upvotes: 11
Views: 4338
Reputation: 25654
Generally I agree with Dario - making this on type level seems impossible.
But you can use classes ("strategy pattern"):
class A {
void evil(A a) { // a pointer to A is ok too
}
};
You can even add operator():
void operator()(A a) { return evil(a); }
Generally such things are better done in FP languages. Haskell version is simply:
data Evil = Evil (Evil -> Integer)
This uses a wrapper (Evil
) that corresponds to using a class.
From the questioner: what this answer lacked was the ability to pass several different functions as an argument of one of them. This can be solved either by making evil()
virtual or by explicitly storing in the object a function pointer that implements it (which is basically the same).
With this clarification, the answer is good enough to be accepted.
Upvotes: 3
Reputation: 1485
Another dirty trick.
void Foo( ... )
{
}
int main()
{
Foo( Foo );
}
Above program will compile without any error. But it is not recursive. Following modified function is recursive version with a limiter.
#define RECURSIVE_DEPTH (5)
typedef void ( *FooType )( int, ... );
void Foo( int Depth, ... )
{
void ( *This )( int, ... );
va_list Arguments;
va_start( Arguments, Depth );
if( Depth )
{
This = va_arg( Arguments, FooType );
This( Depth - 1, This );
}
va_end ( Arguments );
}
int main()
{
Foo( RECURSIVE_DEPTH, Foo );
}
Upvotes: 5
Reputation: 179981
YES
It's a variant of "Can you write a function that returns a pointer to itself?", except that in your case, the function type recursively appears as an argumkent, not as the return type. Herb Sutters answer is reusable, though: wrap the pointer in a forward-declared proxy class.
Upvotes: 4
Reputation: 1248
I don't believe you can have a function that can take itself as an argument in C++ without some kind of trickery, such as putting your function in a class, and having the function take that class as an argument.
Another way that will be possible once the new C++ standard hits is to use lambdas, and have the lambda capture itself. I think it would go something like this:
auto recursive_lambda = [&recursive_lambda] { recursive_lambda(); };
Be warned that such a statement is totally untested in any compiler that supports lambdas. Your mileage may vary.
Upvotes: 1
Reputation: 169673
A related problem is returning a function pointer of same type. It comes up when implementing state machines, so it got its own entry in the C FAQ.
The same workarounds can be applied to your problem.
Upvotes: 2
Reputation: 122489
If a function could take itself as an argument, then it could perform anonymous recursion by calling itself. But recursion is impossible in simply-typed lambda calculus (which is basically what you have here, with function types). You need to implement a fixed-point combinator using recursive functions or recursive types in order to perform anonymous recursion.
Upvotes: 0
Reputation: 146123
This is a perfectly valid use of void *
.
typedef void T(void *);
void f(T *probably_me)
{
(*probably_me)(f);
}
Upvotes: 0
Reputation: 49218
Apparently not - see this thread. The type required here would always be infinite.
Upvotes: 5