2015-02-13 10 views
14

Gibt es eine Standardmethode, um die Typen der Argumente einer Funktion abzurufen und diese Typen als Vorlageparameterpaket weiterzugeben? Ich weiß, dass dies in C++ möglich ist, weil it has been done before.Get-Typen von C++ - Funktionsparametern

Ich habe gehofft, dass hier mit 14 C++ oder dem bevorstehenden C++ 1z, gäbe es einen idiomatischen Weg arg_types<F>... zu implementieren:

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

Nur klar zu sein, eine Antwort behauptet, dass es Keine Standardmethode, dies zu tun, ist keine Antwort. Wenn es keine Antwort gibt, würde ich bevorzugen, dass die Frage unbeantwortet bleibt, bis die Lösung zu C++ 500 hinzugefügt wird oder bis zum Hitzetod des Universums, je nachdem, was früher passiert :)

Edit: Eine gelöschte Antwort darauf hingewiesen, dass ich kann PRETTY_FUNCTION verwenden, um die Namen von Parametertypen abzurufen. Ich möchte jedoch die tatsächlichen Typen. Nicht die Namen dieser Typen.

+0

Sie können nicht Pack Erweiterungen ohne ein nicht ausgedehnten Parameter Pack tun, so dass Syntax steht außer Frage. – Columbo

+1

Sprechen Sie über eine Form der Reflexion? Sie können einen Blick auf den Namen Mangling werfen: Weil C++ - Typen im Symbol kodiert sind, können Sie durch den Zugriff auf Debug-Informationen auf binäre und wissende Funktionsadresse ziemlich genau sagen, was die Parametertypen sind ... –

+1

1. Mit C++ mit FILE ?! ! 2. Bessere Muster als zu versuchen, Typen zur Laufzeit herauszufinden –

Antwort

8

Diese Syntax ist etwas anders.

Erstens, weil Typen leichter zu verarbeiten sind als Packs, ein Typ, der eine Packung enthält. Die using type=types; spart mir nur im Code arbeiten, die eine types erzeugt: Hier

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

ist das Zugpferd. Es nimmt eine Signatur und erzeugt ein types<?...>-Bündel, das die Argumente für die Signatur enthält. 3 Schritte, damit wir schöne saubere C++ 14esque Syntax erhalten:

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; 

Hier ist eine Syntax Unterschied. Anstatt direkt Params... einzunehmen, nehmen wir eine types<Params...>. Dies ist vergleichbar mit dem „Tag Dispatching“ -Muster, wo wir Template-Funktion Typ Abzug ausnutzen Argumente in der Typliste zu verschieben:

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

Mein fopen ist anders, weil ich es will #include nicht die Mühe Sachen ing:

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

und die Syntax wird aus der fopen basiert, sondern vielmehr die Typ von fopen. Wenn Sie einen Zeiger haben, müssen Sie decltype(*func_ptr) oder soetwas tun. Oder wir könnten die oben erweitern R(*)(Args...) für einfache Bedienung zu handhaben:

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

live example.

Beachten Sie, dass dies nicht arbeitet mit überladenen Funktionen, noch funktioniert es mit Funktionsobjekten.

Im Allgemeinen ist diese Art von Sache eine schlechte Idee, weil Sie normalerweise wissen, wie Sie mit einem Objekt interagieren.

Das obige wäre nur nützlich, wenn Sie eine Funktion (oder einen Funktionszeiger) nehmen und einige Argumente von irgendeinem Stapel irgendwo abheben und ihn auf der Basis der erwarteten Parameter oder etwas Ähnlichem aufrufen möchten.

+1

"einige Argumente irgendwo aus irgendeinem Stapel heraus knallen und es basierend auf den Parametern nennen, die es erwartet". Huh, genau das mache ich! – Navin

+1

@Navin selbst dann hätte ich eher "diese Funktion aufrufen, die diese Typen verwendet, die diesen Rückgabewert erwarten" - dh die Signatur unabhängig übergeben. Sie können überprüfen, ob die Signatur * mit dem Aufrufziel funktioniert *. Überladen von Steinen und Überladen verlieren * und * ADL saugt. Oh, und wenn Sie einen Funktionszeiger in 'some_function' übergeben, könnten Sie direkt daraus' Args' ableiten. – Yakk

+0

Verlieren Überlastung und ADL nicht saugen, aber ich benutze dies für C-Funktionen wie 'fopen()'. Wünsch mir Glück. – Navin

2

Verwenden Sie Boost.FunctionTypes und std::index_sequence. Im Folgenden finden Sie ein Beispiel, in dem die Argumenttypen der Funktion func ausgegeben werden.Sie können die statische Funktion doit ändern, um das zu tun, was Sie wollen. Sehen Sie es in Aktion 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; 
} 

Headers (bewegte hier unten Rauschen in dem obigen Codeausschnitt zu verkleinern):

#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

Werfen Sie auch Boost.TypeIndex und Sie erhalten ein sehr lesbares Ergebnis - http://coliru.stacked-crooked.com/a/d9af42b0a48dc867 – Praetorian