2015-02-13 15 views
14

Esiste un modo standard per ottenere i tipi di argomenti di una funzione e passare questi tipi come un pacchetto di parametri del modello? So che questo è possibile in C++ perché it has been done before.Ottieni i tipi di parametri di funzione C++

Speravo che con C++ 14 o l'imminente C++ 1Z, ci sarebbe un modo per implementare idiomatica arg_types<F>... qui:

template <typename ...Params> 
void some_function(); // Params = const char* and const char* 

FILE* fopen(const char* restrict filename, const char* restrict mode); 

int main(){ 
    some_function<arg_types<fopen>...>(); 
} 

Giusto per essere chiari, una risposta sostenendo che non v'è nessun modo standard per farlo non è una risposta. Se non c'è una risposta, preferirei che la domanda rimanga senza risposta fino a quando la soluzione non viene aggiunta a C++ 500 o fino alla morte termica dell'universo, qualunque cosa accada prima :)

Modifica: Una risposta cancellata ha notato che I possibile utilizzare PRETTY_FUNCTION per ottenere i nomi dei tipi di parametri. Tuttavia, voglio i tipi reali. Non i nomi di quei tipi.

+0

Non si può fare espansioni pacchetto senza un parametro di pacchetto non espanso, in modo che la sintassi è fuori discussione. – Columbo

+1

Stai parlando di qualche forma di riflessione? Puoi dare un'occhiata al mangling del nome: poiché il C++ codifica i tipi di argomento nel simbolo, accedendo alle informazioni di debug sull'indirizzo della funzione binaria e conoscente puoi dire con precisione, quali sono i tipi di parametri ... –

+1

1. Usare C++ con FILE ?! ! 2. Modelli migliori di cercare di capire i tipi in fase di esecuzione –

risposta

8

Questa sintassi è leggermente diversa.

In primo luogo, perché i tipi sono più facili da utilizzare rispetto ai pacchetti, un tipo che contiene un pacchetto. Il using type=types; salva solo io lavoro nel codice che genera un types:

template<class...>struct types{using type=types;}; 

Ecco il cavallo di battaglia. Prende una firma e produce un pacchetto types<?...> contenente gli argomenti per la firma. 3 passi così possiamo ottenere bella C++ pulita 14esque sintassi:

template<class Sig> struct args; 
template<class R, class...Args> 
struct args<R(Args...)>:types<Args...>{}; 
template<class Sig> using args_t=typename args<Sig>::type; 

Ecco una differenza di sintassi. Invece di prendere direttamente Params..., prendiamo un types<Params...>. Questo è simile al modello "tag di dispacciamento", in cui sfruttiamo modello tipo di funzione detrazione per spostare argomenti nella lista Tipo:

template <class...Params> 
void some_function(types<Params...>) { 
} 

mio fopen è diverso, perché io non voglio disturbare #include roba ing:

void* fopen(const char* filename, const char* mode); 

E la sintassi non è basato fuori di fopen, ma piuttosto il tipo di fopen. Se hai un puntatore, devi fare decltype(*func_ptr) o somesuch. Oppure potremmo aumentare il top per gestire R(*)(Args...) per facilità d'uso:

int main(){ 
    some_function(args_t<decltype(fopen)>{}); 
} 

live example.

Nota che questo non funziona con funzioni sovraccariche, né funziona con oggetti funzione.

In generale, questo genere di cose è una cattiva idea, perché di solito sai come stai interagendo con un oggetto.

Quanto sopra sarebbe utile solo se si desidera utilizzare una funzione (o un puntatore di funzione) e inserire alcuni argomenti da qualche stack in qualche punto e richiamarlo in base ai parametri previsti o qualcosa di simile.

+1

"espellere alcuni argomenti da qualche stack e chiamarlo in base ai parametri previsti". Huh, è esattamente quello che sto facendo! – Navin

+1

@Navin anche in questo caso, preferirei piuttosto che "invochi questa funzione utilizzando questi tipi che prevedono questo valore di ritorno", ovvero passa la firma in modo indipendente. È possibile ricontrollare che la firma * funzioni * con il target di invocazione. Sovraccarico di rocce e perdita di sovraccarico * e * ADL fa schifo. Oh, e se stai passando un puntatore a funzione in 'some_function', puoi semplicemente dedurre' Args ... 'direttamente da esso. – Yakk

+0

Perdendo sovraccarico e ADL fa schifo, ma mi capita di usarlo per funzioni C come 'fopen()'. Augurami buona fortuna. – Navin

2

Utilizzare Boost.FunctionTypes e std::index_sequence. Di seguito è riportato un esempio che stampa i tipi di argomento della funzione func.È possibile modificare la funzione statica doit per fare ciò che si desidera. Guardalo in azione here.

template <typename FuncType> 
using Arity = boost::function_types::function_arity<FuncType>; 

template <typename FuncType> 
using ResultType = typename boost::function_types::result_type<FuncType>::type; 

template <typename FuncType, size_t ArgIndex> 
using ArgType = typename boost::mpl::at_c<boost::function_types::parameter_types<FuncType>, ArgIndex>::type; 

void func(int, char, double) {} 

template <typename Func, typename IndexSeq> 
struct ArgPrintHelper; 

template <typename Func, size_t... Inds> 
struct ArgPrintHelper<Func, integer_sequence<size_t, Inds...> > 
{ 
    static void doit() 
    { 
    string typeNames[] = {typeid(ResultType<Arg>).name(), typeid(ArgType<Func, Inds>).name()...}; 
    for (auto const& name : typeNames) 
     cout << name << " "; 
    cout << endl; 
    } 
}; 

template <typename Func> 
void ArgPrinter(Func f) 
{ 
    ArgPrintHelper<Func, make_index_sequence<Arity<Func>::value> >::doit(); 
} 

int main() 
{ 
    ArgPrinter(func); 
    return 0; 
} 

intestazioni (trasferiti qui per ridurre il rumore nel frammento di codice di cui sopra):

#include <boost/function_types/function_type.hpp> 
#include <boost/function_types/parameter_types.hpp> 
#include <boost/function_types/result_type.hpp> 
#include <boost/function_types/function_arity.hpp> 

#include <algorithm> 
#include <iostream> 
#include <string> 
#include <type_traits> 
#include <typeinfo> 
#include <tuple> 
#include <utility> 
using namespace std; 
+4

Inserisci anche Boost.TypeIndex e ottieni un risultato molto leggibile - http://coliru.stacked-crooked.com/a/d9af42b0a48dc867 – Praetorian

Problemi correlati