Self-relational type

What type T makes the following code compile?

T f(){ return &f; } 

I would prefer a C answer, but I posed the question as C and C ++ in case there is only an answer using templates.

+4
source share
8 answers

I hope this is not a hoax (C ++ only):

 class T { private: T (*_func)(); public: T(T (*func)()) : _func(func) {} T operator()() { return *this; } }; T f() { return &f; } int main() { f()()()()()()()(); } 
+9
source

An interesting problem, but without an acceptable solution to C, I think.

Why is this not possible with C? (some specs here)

Return function type T:

 T (*)(void) ; 

Which expects T to be defined, of course ... But then, since T is a type of the function itself, there is a circular dependence.

For structure T, we could have:

 struct T ; /* forward declaration */ typedef T * (*f)(void) ; /* f is a function returning a pointer to T */ 

Were the following notation convenient?

 function T ; /* fictional function forward-declaration. It won't compile, of course */ TT(void) ; /* function declaration */ 

But since there is no way to forward-declare a function, then there is no way to use the construct that you wrote in your question.

I am not a compiler lawyer, but I believe that this circular dependency is created only because of the typedef record, and not because of the C / C ++ restriction. In the end, function pointers (I'm talking about functions here, not object methods) are the same size (just like structure or class pointers are the same size).

Learning C ++ Solution

As for C ++ solutions, the previous answers gave good ones (I think of zildjohn01 answer , here).

An interesting point is that they are all based on the fact that structures and classes can be declared ahead (and are considered forward declared in their declaration):

 #include <iostream> class MyFunctor { typedef MyFunctor (*myFunctionPointer)() ; myFunctionPointer m_f ; public : MyFunctor(myFunctionPointer p_f) : m_f(p_f) {} MyFunctor operator () () { m_f() ; return *this ; } } ; MyFunctor foo() { std::cout << "foo() was called !" << std::endl ; return &foo ; } MyFunctor barbar() { std::cout << "barbar() was called !" << std::endl ; return &barbar ; } int main(int argc, char* argv[]) { foo()() ; barbar()()()()() ; return 0 ; } 

What outputs:

 foo() was called ! foo() was called ! barbar() was called ! barbar() was called ! barbar() was called ! barbar() was called ! barbar() was called ! 

Inspiration from a C ++ solution to achieve a C solution

Could you use a similar method in C to achieve comparable results?

Somehow, yes, but the results are not as sexy as C ++ - solution:

 #include <stdio.h> struct MyFuncWrapper ; typedef struct MyFuncWrapper (*myFuncPtr) () ; struct MyFuncWrapper { myFuncPtr f ; } ; struct MyFuncWrapper foo() { printf("foo() was called!\n") ; /* Wrapping the function */ struct MyFuncWrapper w = { &foo } ; return w ; } struct MyFuncWrapper barbar() { printf("barbar() was called!\n") ; /* Wrapping the function */ struct MyFuncWrapper w = { &barbar } ; return w ; } int main() { foo().f().f().f().f() ; barbar().f().f() ; return 0 ; } 

What outputs:

 foo() was called! foo() was called! foo() was called! foo() was called! foo() was called! barbar() was called! barbar() was called! barbar() was called! 

Conclusion

You will notice that the C ++ code is very similar to the C code: each source will use the structure as a container for the function pointer, and then use the pointer contained in the callback if necessary. Of course, the C ++ solution uses operator () overloading, makes characters private, and uses a specific constructor as syntactic sugar.

(Here's how I found a C solution: trying to reproduce C ++ - a "manual" solution)

I don't believe that we could make better use of syntactic sugar C using macros, so we stick to this C solution, which I find far from impressive, but still wondering how long it took me to find it.

After all, finding solutions to bizarre problems is a surefire way to find out ...

:-)

+9
source

How does the C FAQ Question 1.22 explain that this is not possible in C. Workarounds include moving the function pointer to a struct and returning it or returning another (arbitrary) type of function pointer, which is possible since casting between types of function pointers is loss-free.

+4
source

Funny, I thought about this exact thing recently (only I wanted the function to take a pointer to itself, and not return it).

For C ++, you already have an answer from zildjohn01.

If we adhere to the C standard, there is no solution that compiles in exactly the same way as it is written. You can disable it with an explicit cast - void* will not work because converting a pointer to a pointer to a data pointer is not standard, but you can use any other type of function pointer (for example, void(*)() will do) - Standard explicitly allows casting from any type of function pointer to any other type of function and vice versa, and ensures that you get the original value.

+2
source

The answer to this question will cost no less than your eternal soul.

+1
source

In C ++ it is easy:

 struct my_function { my_function& operator()() { return *this; } }; 

In C, you will need to impose void * s, which will work in any reasonable implementation, but, in my opinion, is technically undefined.

It would be nice if both languages ​​allowed simple recursive types. Alas, they do not.

0
source

No type makes this compatible, since you must have infinite recursion in typedef.

You can, however, do tricks like DrPizza to simulate. However, you can never do it literally.

Supported by the miracle auto / decltype:

 auto f() -> decltype(&f) { return &f; } = a shitload of errors. 
0
source

There is no reason that the end of the C compiler C could not handle this, and a good interface (except for the analyzer and the omission of a character) could also. But the way that C is defined makes it impossible to get data to later bits of the compiler. The OTOH C compiler, which implements typdefs via a link and is not suitable for populating typedefs in a character table before it resolves the characters they use, will actually swallow it just fine.

0
source

Source: https://habr.com/ru/post/1312916/


All Articles