2010-01-22 10 views
6

Per quanto strano possa sembrare, ho bisogno di chiamare una funzione in C++, per la quale non conosco la firma. Fondamentalmente, voglio consentire all'utente di specificare un elenco di argomenti e tipi di argomenti e quindi provare a chiamare una determinata funzione con questi argomenti. Vorrei quindi sapere se la chiamata alla funzione ha funzionato o meno, e se lo ha fatto (miracolosamente), qual è il valore di ritorno (a condizione che il tipo di reso non sia nullo). C'è un modo per riuscirci? Grazie.Chiamata di funzione C++ con i parametri sconosciuti al momento della compilazione

+5

Penso che una domanda importante sia * "Perché?" * C'è probabilmente un modo molto più semplice. – GManNickG

+0

Chiamerai sempre la stessa funzione? Oppure l'argomento/elenco parametri seleziona la funzione che verrà chiamata? –

+0

Sì, sembra che tu abbia qualcosa che vuoi veramente fare con questo piccolo esperimento mentale. Che cos'è? – Omnifarious

risposta

0

Non sembra strano, ma non è possibile farlo in C++. Le firme delle funzioni C++ vengono verificate in fase di compilazione. Il meglio che puoi fare è passare un vettore, o un contenitore simile, contenente i parametri della funzione per la funzione. Anche allora, i tipi (o almeno il tipo di base, se si utilizza l'ereditarietà) dovrebbero essere noti al momento della compilazione.

+0

@Neil Butterworth: La tua conclusione potrebbe essere giusta, ma il tuo ragionamento è fallace. Lo stesso vale per C# (tipizzato staticamente), ma è possibile fare ciò che l'OP sta richiedendo usando la reflection. Sì, so che il C++ non ha capacità di riflessione. – jason

+1

Ovviamente. Il C++ ti consente di fare qualsiasi cosa, ma a quale scopo? Sembra improbabile che l'OP voglia scrivere un meccanismo di riflessione generico per C++. –

+0

@Neil Butterworth: sono d'accordo. E la domanda suggerisce un grande odore di design. – jason

0

Se si ha accesso al compilatore C++ durante l'esecuzione, è possibile scrivere la chiamata postulata in un file, compilarlo, quindi collegarlo dinamicamente come una DLL e provare a eseguirlo. Se i tipi di argomento sono errati o la funzione non esiste, il collegamento di runtime DLL non riesce; altrimenti la funzione viene chiamata e si ottiene il valore di ritorno.

5

Consenti alle tue funzioni di prendere un elenco di tipi di dati varianti, ad es. std::vector<boost::any> e fare in modo che restituiscano un bool che indica il successo o genera eccezioni in caso di errore.

Se si sta bene registrando le funzioni esposte in fase di compilazione, non è nemmeno necessario posizionare tale restrizione sulle proprie funzioni e si può invece generare codice di colla per le conversioni necessarie.

+0

+1 boost :: variante potrebbe anche essere utilizzata –

+0

E se la funzione deve restituire valori di tipi diversi, restituire una variante. O qualche altro tipo discriminato. Boost non è richiesto. Potresti consegnare facilmente qualcosa per le tue esigenze specifiche. –

+1

Cioè, un 'unione'. Penso che la "variante" sia un'ottima idea, anche se ... parlo MOLTO relativamente. – Potatoswatter

3

Naturalmente è possibile farlo in fase di esecuzione. Gdb, per esempio, lo fa. Ma richiede molto lavoro e comprensione dell'ambiente di destinazione. Sospetto che ci possa essere un modo migliore per fare ciò che vuoi.

+1

Tuttavia, Gdb non lo fa "in C++"."Comprensione dell'ambiente di destinazione" cambia radicalmente il problema. –

0

Bene, se si è flessibili sul meccanismo, è possibile fare questo genere di cose utilizzando la spedizione dinamica.

Quello che devi fare è creare una classe base astratta che ha un metodo "esegui" che restituisce un valore di ritorno. Quindi hai un motore che mantiene una lista di puntatori agli oggetti di questa classe di base (astratta), che i clienti possono fornirti tramite una sorta di chiamata di registrazione.

I client scrivono le proprie implementazioni di "esegui" che possono fare tutto ciò che è necessario, a patto che riempiano correttamente il valore di ritorno del motore quando hanno finito. I loro "parametri personalizzati" sono implementati come membri extra della loro versione della classe, che possono essere compilati quando costruiscono l'oggetto, o da una chiamata separata.

Questo ti dà ciò di cui hai bisogno per chiamare la loro routine, eseguirla e controllare il risultato, senza dover sapere quali sono i loro parametri personalizzati o esattamente cosa fa la loro routine.

-1

Questo suona come un sitter per includere un linguaggio di scripting digitato in modo dinamico nella tua app. Incorporare qualcosa come Lua o Python, rendere disponibili le funzioni che si desidera chiamare al linguaggio di scripting. Oppure, se stai cercando di implementare una cosa del genere, guarda Boost :: Python come un precedente su come farlo.

0

Questa è una domanda senza senso, dal momento che se l'utente (chi sta chiamando da c-codice) non conosce il tipo di argomento a tempo di compilazione, sarà non essere in grado di fornire gli argomenti della corretto tipo, anche se fosse possibile costruire un puntatore a funzione digitata in modo dinamico.

Anche l'esempio gdb espresso in un'altra risposta presuppone che l'utente disponga di variabili del tipo appropriato e noto al punto della chiamata.

Poiché ciò è vero, deduco che l'utente conosca i tipi corretti dell'argomento e questo diventa quindi una questione su come creare una funzione in fase di compilazione che richiede un insieme di argomenti di tipo noto.

Ciò si ottiene semplicemente: Se l'utente ha un int e due float s e spera di ottenere un int in cambio, e vuole chiamare la funzione presunta swizzle il cui tipo di conseguenza deve essere int (IIIF*)(int, int, float), poi semplicemente dichiarare un puntatore di questa digitare, utilizzare ldload per ottenere la funzione swizzle e richiamarla.

Ci sono, tuttavia, alcuni casi speciali di questo che potresti essere in grado di raggiungere, ad esempio, se tutti gli argomenti sono puntatori.

noti che noto al momento della compilazione include casi come modelli, i cui valori sono inferita al momento della compilazione di informazioni di tipo esplicito o implicito al punto e il modello tempo istanziazione.

0

Come utilizzare i riferimenti di rvalue in C++ ox?

template<typename Function> 
void FunCall(Function&& f) 
{ 
    f(); 
} 

void Fun_Int(int x) 
{ 
    using std::cout; 
    using std::endl; 

    cout << "I''m Fun_Int with " << x << endl; 
} 

void Fun_Str(const string& str1) 
{ 
    using std::cout; 
    using std::endl; 
    cout << "I'm Fun_Str with " << str1 << endl; 

} 

void RvaluesDemo() 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     FunCall([&] 
     { 
      Fun_Int(i); 
     }); 
    } 

    string str = "ABCDEF"; 

    for (int i = 0; i < str.size(); i++) 
    { 
     ostringstream os; 
     os << str[i]; 

     FunCall([&] 
     { 
      Fun_Str(os.str()); 
     }); 
    } 
} 
Problemi correlati