2015-09-27 34 views
10

Desidero assegnare l'indirizzo di una funzione a un puntatore di funzione, ma la funzione da indirizzare restituisce un puntatore a funzione con la stessa firma di se stesso, provocando il recurse in modo che non possa scrivere il tipo di ritorno, per il puntatore a funzione o anche la dichiarazione di funzione in sé ...Come scrivere un puntatore a una funzione che restituisce un puntatore a una funzione?

Credo che un modo di semplificare il problema quindi non è fonte di confusione:

Come potrei scrivere una dichiarazione di funzione tale che può restituire un puntatore a stesso (o qualsiasi altra funzione con la stessa firma)?

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

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

edit:

Per ora ho una soluzione, anche se non posterò come una risposta, perché è aggressivo brutto. E si libera della ricorsione, semplicemente restituendo un void* puntatore crudo come il tipo di ritorno, e finisce per prendere il seguente modulo:

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

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

EDIT2:

Sembra fusione tra puntatori a funzione e puntatori regolari è UB, quindi in questo caso non posso usare

Per rispondere a uno dei commenti, questo è per passare il controllo tra più loop "principali" nel mio programma, con ogni ciclo che ottiene la sua funzione. Ci sono molti modi per farlo, ma restituendo i puntatori di funzione (o NULL per terminare il programma) il mid-loop sembrava il come il metodo più semplice, ma non avevo previsto che i puntatori ai dati e i puntatori agli indirizzi di funzione sarebbero stati incomparabili insieme. Penso che restituire oggetti funzione polimorfici finirà per essere l'opzione più sensata in questo caso.

+1

te immagino non posso farlo, almeno non facilmente. –

+0

Mi chiedo se restituire 'void *' come tipo di ritorno del puntatore funzione e funzione, mi consentirà di evitare la dichiarazione ricorsiva ... –

+0

BTW, anche Ocaml non lo consente, a meno che non si invochi 'ocamlc' con' -rectypes' (per * tipi ricorsivi *) –

risposta

6

Non utilizzare void*, perché non garantisce che un void * possa contenere un puntatore di funzione. È possibile utilizzare void(*)() come una soluzione:

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 puntatore a void hanno gli stessi requisiti di rappresentatività e di allineamento come un puntatore a un tipo di carattere. Allo stesso modo, i puntatori alle versioni quali fi nite fi cate o non qualificate di tipi compatibili devono avere lo stesso requisiti di rappresentazione e allineamento. Tutti i puntatori ai tipi di struttura devono avere la stessa rappresentazione e allineamento i requisiti tra loro. Tutti i puntatori ai tipi di unione devono avere lo stesso requisiti di allineamento e di rappresentazione reciproci. I puntatori ad altri tipi non devono avere la stessa rappresentazione o allineamento requisiti.

C99 [6.3.2.3/8]:

Un puntatore a una funzione di un tipo può essere convertito in un puntatore a una funzione di un altro tipo e viceversa; il risultato deve confrontare uguale al puntatore originale.

+2

tuttavia non può restituire nulla, poiché 'func' dovrà corrispondere alla funzione che lo ha restituito, che restituisce' func' –

+1

Nota che la conversione di un puntatore a una funzione 'void *' è UB e non è necessario che sia supportato né che il suo valore viene preservato durante la conversione avanti e indietro. – edmz

+1

@PiotrSkotnicki Ho risolto la mia risposta. – songyuanyao

5

Il trucco in C è quello di approfittare del fatto che qualsiasi tipo di puntatore a funzione può essere lanciato da qualsiasi altro tipo di puntatore a funzione:

#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; 
} 

Ogni puntatore ad una strategia è sempre in una digitare che può essere chiamato una volta, e il valore restituito viene ricollocato in un modulo che può essere richiamato ancora una volta.

In C++, si dovrebbe dichiarare un oggetto funzione:

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

Un'istanza di questa classe può essere chiamato come una funzione.

+0

Come restituire un riferimento di un altro oggetto funzione da una funzione membro? – songyuanyao

+0

@songyuanyao Non sono sicuro di aver capito la domanda, ma un approccio sarebbe quello di fare della strategia una classe base astratta e avere sottoclassi che implementano strategie diverse. Quindi potresti restituire istanze di quelli. – Davislor

+0

Intendo in una sottoclasse, quando si restituisce un'altra sottoclasse, è necessario mantenere valido il riferimento, utilizzando la variabile globale, ecc. – songyuanyao

1

ho il sospetto ciò che si sta cercando di fare è una versione più complessa di qualcosa di simile a questo:

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(); 
    } 
} 

Una soluzione è quella di avvolgere il puntatore a funzione in una struct:

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(); 
    } 
} 
+0

Il problema nella domanda è l'analogo di funzione-puntatore di dichiarare una lista collegata, e questa risposta è come lo si fa in entrambi i casi. – PBS

Problemi correlati