2010-01-05 6 views
8

Sto cercando un modo in C++ per estrarre il tipo di ritorno di una funzione (senza chiamarla). Presumo che questo richiederà un po 'di magia del modello.Estrarre il tipo di ritorno di una funzione senza chiamarla (utilizzando i modelli?)

float Foo(); 
int Bar(); 

magic_template<Foo>::type var1; // Here 'var1' should be of type 'float' 
magic_template<Bar>::type var2; // and 'var2' should be of type 'int' 

Attualmente sto studiando come potrebbe essere implementato magic_template, ma non ho trovato finora una soluzione.

Qualche idea?

risposta

7

Dai un'occhiata alla libreria boost type traits, in particolare il modello function_traits fornisce tale funzionalità fuori dalla scatola. Se non puoi usare boost, scarica il codice e leggi i sorgenti per capire come è fatto.

Si noti che la funzionalità è basata su tipi, non su funzioni concrete, quindi potrebbe essere necessario aggiungere del codice aggiuntivo.


Dopo aver fatto alcuni piccoli test, questo potrebbe non essere ciò che si ha realmente bisogno, e se è il 'po' di codice in più' sarà non banale. Il problema è che il modello function_traits funziona con le firme delle funzioni e non con i puntatori effettivi delle funzioni, quindi il problema è cambiato da "ottenere il tipo di ritorno da un puntatore a" a "ottenere la firma da un puntatore di funzione" che è probabilmente la parte più difficile lì .

+1

I tipi di ritorno delle funzioni sono covarianti, un iceberg che affonderà quel Titanic. –

+0

Hmm sì, questo sembra. Per dare un esempio a tutti funziona così: boost :: function_traits :: type> :: result_type var1; var1 = 3,14f; Il mio unico problema ora è come hai detto, ho bisogno del tipo dell'intera funzione per passare a queste utility di potenziamento. – pauldoo

+0

@nobugz: Non capisco davvero il tuo commento, puoi spiegarlo ulteriormente? –

-1

provare qualcosa di simile:

template<class T> struct magic_template 
{}; 

template<class T> struct magic_template<T()> 
{ 
    typedef T type; 
}; 
5

E 'difficile perché i nomi delle funzioni sono espressione non tipi - avete bisogno di qualcosa come gcc di typeof. Boost's TypeOf è una soluzione portatile che si avvicina molto.

Tuttavia, se il codice può essere organizzato in modo che il lavoro è fatto all'interno di un modello di funzione a cui Foo o Bar possono essere passati, c'è una risposta diretta:

template <class R> 
void test(R (*)()) 
{ 
    R var1; 
} 

int main() 
{ 
    test(&Foo); 
} 
4

Foo e Bar sono funzioni , non i tipi di funzione, quindi è necessario fare un po 'di lavoro extra.

Ecco una soluzione che utilizza una combinazione di boost :: function_traits e BOOST_TYPEOF.

#include <boost/typeof/typeof.hpp> 
#include <boost/type_traits.hpp> 

float Foo(); 
int Bar(); 

int main() 
{ 
    boost::function_traits<BOOST_TYPEOF(Foo)>::result_type f = 5.0f; 
    boost::function_traits<BOOST_TYPEOF(Bar)>::result_type i = 1; 
    return i; 
} 

Edit:

  • Questo funziona per le funzioni di qualsiasi arietà fino a 10, che dovrebbe essere sufficiente per gli usi più sensibili.
  • Questo uso di BOOST_TYPEOF funziona su piattaforme che non forniscono un tipo nativo, quindi è ragionevolmente portatile.
0

Come suggerito da dribeas, ecco la soluzione alla fine ho venuto a:

float Foo(); 
int Bar(); 

template<typename T> Monkey(T) { 
    boost::function_traits< boost::remove_pointer<T>::type >::result_type var1 = ...; 
    // Now do something 
} 

Monkey(Foo); 
Monkey(Bar); 

Questo non è esattamente la forma ho puntato per la mia domanda iniziale, ma è abbastanza vicino per me.

+0

Hai bisogno di un altro 'typename' in lì: typename boost :: function_traits :: type> :: result_type –

+0

Potresti perdere il remove_pointer solo facendo la signature void Monkey (T *) [oh sì, hai perso anche il tipo di ritorno di Monkey] –

1

Arriva la magia modello (senza Boost è coinvolto) :

template <typename ReturnType> class clFunc0 
{ 
    typedef ReturnType (*FuncPtr)(); 
public: 
    typedef ReturnType Type; 
}; 

template <typename ReturnType> inline clFunc0<ReturnType> ResultType(ReturnType (*FuncPtr)()) 
{ 
    return clFunc0<ReturnType>(); 
} 

#define FUNC_TYPE(func_name) decltype(ResultType(&func_name))::Type 

int test() 
{ 
    return 1; 
} 

int main() 
{ 
    FUNC_TYPE(test) Value = 1; 

    return Value; 
} 

e compilarlo via

gcc Test.cpp -std=gnu++0x 
+1

Non ce n'è bisogno in C++ 11, che ha 'std :: result_of'. – Potatoswatter