Comment écrire un pointeur de fonction à une fonction retournant un pointeur de fonction vers une fonction?

je veux assigner l'adresse d'une fonction à un pointeur de fonction, mais la fonction à adresser renvoie un pointeur de fonction avec la même signature que lui, ce qui le fait réapparaître d'une manière que je ne peux pas écrire le type de retour du tout, pour le pointeur de fonction ou même la déclaration de fonction elle-même...

j'imagine, une façon de simplifier le problème, donc ce n'est pas à confusion:

Comment pourrais-je écrire une déclaration de fonction telle, qu'elle puisse retourner un pointeur vers elle-même (ou toute autre fonction avec la même signature)?

????? function(int a){
    // could be this function, or another with the same signature, 
    return arbitraryFunction;  
}

?????(*func)(int) = function;  // same problem as above

edit:

pour l'instant j'ai une solution, mais je ne la posterai pas comme réponse parce que c'est agressivement laid. Il se débarrasse de la récursion en retournant simplement un raw void* pointeur comme type de retour, et finit par prendre la forme suivante:

void* function(int parameter){
    return arbitraryFunction; // of the same signature
}

void*(*func)(int) = function; 
func = reinterpret_cast<void*(*)(int)>(func(42));  // sin

edit2:

il semble que le casting entre les pointeurs de fonction et les pointeurs réguliers est UB, donc je ne peux pas utiliser void* dans ce cas...

pour répondre à l'un des commentaires, ceci est pour passer le contrôle entre plusieurs boucles "principales" dans mon programme, avec chaque boucle obtenant sa propre fonction. Il y a beaucoup de façons de faire cela, mais retourner les pointeurs de fonction (ou NULL pour terminer le programme) à mi-boucle semble comme la méthode la plus simple, mais je n'ai pas prévu que les pointeurs vers les données et les pointeurs vers les adresses de fonction seraient incompréhensibles entre eux. Je pense que le retour les objets de fonction polymorphique seront finalement l'option la plus saine dans ce cas.

10
demandé sur Anne Quinn 2015-09-27 18:04:48

3 réponses

Ne pas utiliser void*, car aucune garantie qu'un void * peut contenir un pointeur de fonction. Vous pouvez utiliser void(*)() solution:

typedef void(*void_func)();
typedef void_func (*func_type) (int);
void_func arbitraryFunction(int a) {
    // could be this function, or another with the same signature, 
    cout << "arbitraryFunction\n";
    return nullptr;  
}
void_func function(int a) {
    // could be this function, or another with the same signature, 
    return (void_func) arbitraryFunction;  
}
int main() {
    // your code goes here
    func_type f = (func_type) function(0);
    f(0);
    return 0;
}

LIVE

C99 [6.2.5 / 27]:

un pointeur à vide doit avoir les mêmes exigences de représentation et d'alignement qu'un pointeur à caractère. De même, des pointeurs vers des qualifié ou non qualifié versions de types compatibles ont le mêmes exigences de représentation et d'harmonisation. Tous les pointeurs vers les types de structure doivent avoir la même représentation et le même alignement les exigences des uns et des autres. Tous les indicateurs des types d'union doivent avoir la les mêmes exigences de représentation et d'harmonisation. Pointeur pour les autres types n'ont pas besoin d'avoir la même représentation ou l'alignement exigence.

C99 [6.3.2.3 / 8]:

Un pointeur vers une fonction d'un type peut être converti en un pointeur vers une fonction d'un autre type et de retour à nouveau; le résultat doit comparer égale au pointeur original.

6
répondu songyuanyao 2015-09-28 02:16:36

Le truc C est de profiter du fait que n'importe quel type de pointeur de fonction peut être converti en un autre type de pointeur de fonction:

#include <stdlib.h>
#include <stdio.h>

typedef void(*emptyfunc)(void);
typedef emptyfunc (*funcptr2)(int);

funcptr2 strategy(int m)
{
  printf("Strategy %d.\n", m);
  return (funcptr2)&strategy;
}

int main (void)
{
  const funcptr2 strategy2 = (funcptr2)strategy(1);
  const funcptr2 strategy3 = (funcptr2)strategy2(2);
  strategy3(3);

  return EXIT_SUCCESS;
}

chaque pointeur vers une stratégie est toujours dans un type qui peut être appelé une fois, et la valeur de retour est remise dans une forme qui peut être appelée une fois de plus.

en C++, vous déclareriez un objet de fonction:

class strategy {
  public:
  virtual const strategy& operator()(int) const = 0;
}

Une instance de cette classe peut être appelée comme une fonction.

5
répondu Davislor 2015-09-27 20:58:27

je soupçonne que ce que vous essayez de faire est une version plus complexe de quelque chose comme ceci:

typedef MainLoop *MainLoop(); // not legal

extern MainLoop* main_loop_1();
extern MainLoop* main_loop_2();

MainLoop* main_loop_1()
{
    // do some work here
    return main_loop_2;
}

MainLoop* main_loop_2()
{
    // do some work here
    return main_loop_1;
}

int main()
{
    MainLoop f = main_loop_1;

    for (;;) {
      f = f();
    }
}

une solution consiste à envelopper le pointeur de fonction dans une structure:

struct MainLoop {
    MainLoop (*function_ptr)(); // legal
};

extern MainLoop main_loop_1();
extern MainLoop main_loop_2();

MainLoop main_loop_1()
{
    // do some work here
    return {main_loop_2};
}

MainLoop main_loop_2()
{
    // do some work here
    return {main_loop_1};
}  

int main()
{
    MainLoop f{main_loop_1};

    for (;;) {
       f = f.function_ptr();
    }
}
1
répondu Vaughn Cato 2015-09-27 17:56:54