2016-07-20 3 views
2

Ist es möglich, eine Vorlage zu schreiben, um den Rückgabetyp und den Argumenttyp des Funktionszeigertyps zu extrahieren, in den eine Klasse konvertiert werden kann? Beispiel:Extrahieren von Rückgabe- und Argumenttypen von einem Konvertierungsoperator zum Funktionszeiger

struct Foo { 
    using FnPtr = int (*)(char, double); 

    operator FnPtr() const { ... } 
}; 

// Can I extract the return type (int) and argument types (char and double), 
// knowing only `Foo` as an opaque type? 

Antwort

6

Wenn Foo keine anderen Konvertierungsoperatoren hat und definieren keine Indirektionsoperator, dann können Sie sich darauf verlassen, dass *a_foo einen Verweis auf eine Funktion des gewünschten Typs geben. Von diesem müssen Sie nur die Rückkehr und die Argumente extrahieren.

func_ref_traits hier wird die Extraktion tun:

template <typename Func> 
struct func_ref_traits; 

template <typename Ret, typename... Args> 
struct func_ref_traits<Ret(&)(Args...)> { 
    using ret = Ret; 
    using args = std::tuple<Args...>; 
}; 

Dann conv_func_traits wird den Funktionstyp aus der angegebenen Art ausrechnen:

template <typename T> 
using conv_func_traits = func_ref_traits<decltype(*std::declval<T>())>; 

du wie so verwenden würde:

conv_func_traits<Foo>::args //std::tuple<char,double> 
conv_func_traits<Foo>::ret //int 
+0

Ich denke, das ist wahrscheinlich das Beste, was wir bekommen können. Vielen Dank! –

3

Hier gehts:

#include <type_traits> 

template <typename...> struct typelist; 

template <typename> struct Extract; 

template <typename R, typename ...Args> 
struct Extract<R(*)(Args...)> 
{ 
    using Result = R; 
    using Arguments = typelist<Args...>; 
}; 



template <typename T> 
using Return_Type = typename Extract<typename T::FnPtr>::Result; 

template <typename T> 
using Arguments = typename Extract<typename T::FnPtr>::Arguments; 




struct Foo 
{ 
    using FnPtr = int (*)(char, double); 
}; 


int main() 
{ 
    static_assert(std::is_same<Return_Type<Foo>, int>::value, ":("); 
    static_assert(std::is_same<Arguments<Foo>, typelist<char, double>>::value, ":("); 
} 

Ich habe eine Typenliste verwendet, um die Argumente darzustellen, könnten Sie std::tuple verwenden, wenn Sie das besser mögen. Darüber hinaus benötigen Sie möglicherweise weitere Spezialisierungen von Extract, um verschiedene Arten aufrufbarer Dinge abzudecken.

+1

Aber 'Foo' ist nur als * opaque * -Typ bekannt, daher kann ich den' FnPtr'-Teil leider nicht benutzen. –