function traits.html
獲取函數或成員函數的返回類型,參數類型,參數長度,類類型。ide
函數參數列表推斷基於typelist:http://www.cnblogs.com/flytrace/p/3551414.html函數
先看一個普通函數非const的特化:測試
template<typename R, typename... Args> struct function_traits<R (Args...)> { typedef R return_type; typedef typelist<Args...> arglist; enum { arg_count = sizeof...(Args) }; template<unsigned int N> struct arg { typedef typename at<N, arglist>::type type; }; };
使用:spa
int testfunc1(char) { return 1; } int main() { bool b; b = std::is_same< typename function_traits<int(double)>::return_type, int>::value; std::cout << "is same: " << b << std::endl; b = std::is_same< typename function_traits<decltype(testfunc1)>::arg<0>::type, char>::value; std::cout << "is same: " << b << std::endl; }
對於各類參數類型的普通函數,都能正確推斷。但重載函數的情形須要咱們考慮。以下咱們增長testfunc1的重載版本:指針
bool testfunc1(double, char) { return false; }
此時decltype(testfunc1)是沒法編譯經過的。這並非咱們的function_traits有問題。而是在沒信息的狀況下,decltype是沒法選擇testfunc1的重載版本的。除非咱們在function_traits顯式特化。code
函數指針的function_traits也會遇到重載問題,以下是針對函數指針的function_traits:htm
template<typename R, typename... Args> struct function_traits<R (*)(Args...)> { typedef R return_type; typedef typelist<Args...> arglist; enum { arg_count = sizeof...(Args) }; template<unsigned int N> struct arg { typedef typename at<N, arglist>::type type; }; };
decltye(&testfunc1)也是沒法編譯經過的。很顯然,你本身做爲編譯器做者的話,如果沒有額外的信息,讓你使用decltype去推斷一個可重載的函數類型,你怎麼可以知道用戶但願獲得哪一個類型?除了顯示特化以提供給編譯器信息外,對於函數指針,咱們還能夠提早轉換,顯式給以類型信息供編譯器推斷,以下:blog
int (*castfunc)(char) = &testfunc1;
b = std::is_same< typename function_traits<decltype(castfunc)>::arg<0>::type, char>::value; std::cout << "is same: " << b << std::endl;
castfunc1在定義時獲得了testfunc1正確的重載類型,所以decltype在推斷castfunc時就有了信息來選擇正確的類型。get
這並非一個程序技術問題,更算是一個邏輯問題,就好像面對有多個定義的單詞,沒有上下文你是沒法知道它要表明什麼意思的。
這種顯示轉換並不會帶給咱們太多困擾。由於使用function_traits的場景,基本上是一種延遲推斷手段。好比獲得消息後,使用泛型手法分發消息處理。而消息處理函數咱們在註冊的時候確定是知道函數類型的,在註冊時咱們就已經能夠顯示轉換這個函數指針而不會遇到重載問題了。直接使用decltype(testfunc1)好像在咱們測試function_traits時纔會遇到,嗯,另外一我的也遇到了,否則我不會試驗。。。
然而確實存在一個可能,使咱們能夠傳入testfunc1,而不用給予完整類型信息,雖然不適用於function_traits的狀況。以下:
template<typename ...Args> struct OverloadResolved { template<typename R> static auto static_doit( R (*f) (Args...), Args ... args ) -> R { return f(args...);} }; template<typename ...Args> auto deduce(Args...) -> OverloadResolved<Args...> { return OverloadResolved<Args...>(); } template<typename T> struct dummy : public T { }; #define doit(f, ...) ( dummy<decltype(deduce( __VA_ARGS__ ))> :: static_doit(f, __VA_ARGS__) )
使用:
char aa = 'a'; double ff = 0.1; std::cout << doit(testfunc1, aa) << " " << doit(testfunc1, ff, aa) << std::endl;
能夠看到,雖然testfunc1有2個重載版本,但仍能正確的執行testfunc1(aa)和testfunc1(ff, aa).
固然由於此處給出了參數信息。這是一個運行時方案,而function_traits要求咱們在編譯期就推斷。
如下添加類成員函數的function_traits:
template <typename R, typename T, typename... Args> struct function_traits<R (T::*)(Args...)> { typedef T class_type; typedef R return_type; typedef typelist<Args...> arglist; enum { arg_count = sizeof...(Args) }; template<unsigned int N> struct arg { typedef typename at<N, arglist>::type type; }; };
還須要添加const,volatile修飾符的。如下是更完整的版本:
template<typename T> struct function_traits; template<typename R, typename... Args> struct function_traits<R (Args...)> { typedef R return_type; typedef typelist<Args...> arglist; enum { arg_count = sizeof...(Args) }; template<unsigned int N> struct arg { typedef typename at<N, arglist>::type type; }; }; template<typename R, typename... Args> struct function_traits<R (Args...) const> { typedef R return_type; typedef typelist<Args...> arglist; enum { arg_count = sizeof...(Args) }; template<unsigned int N> struct arg { typedef typename at<N, arglist>::type type; }; }; template<typename R, typename... Args> struct function_traits<R (Args...) volatile> { typedef R return_type; typedef typelist<Args...> arglist; enum { arg_count = sizeof...(Args) }; template<unsigned int N> struct arg { typedef typename at<N, arglist>::type type; }; }; template<typename R, typename... Args> struct function_traits<R (Args...) const volatile> { typedef R return_type; typedef typelist<Args...> arglist; enum { arg_count = sizeof...(Args) }; template<unsigned int N> struct arg { typedef typename at<N, arglist>::type type; }; }; template<typename R, typename... Args> struct function_traits<R (*)(Args...)> { typedef R return_type; typedef typelist<Args...> arglist; enum { arg_count = sizeof...(Args) }; template<unsigned int N> struct arg { typedef typename at<N, arglist>::type type; }; }; template <typename R, typename T, typename... Args> struct function_traits<R (T::*)(Args...)> { typedef T class_type; typedef R return_type; typedef typelist<Args...> arglist; enum { arg_count = sizeof...(Args) }; template<unsigned int N> struct arg { typedef typename at<N, arglist>::type type; }; }; template <typename R, typename T, typename... Args> struct function_traits<R (T::*)(Args...) const> { typedef T class_type; typedef R return_type; typedef typelist<Args...> arglist; enum { arg_count = sizeof...(Args) }; template<unsigned int N> struct arg { typedef typename at<N, arglist>::type type; }; }; template <typename R, typename T, typename... Args> struct function_traits<R (T::*)(Args...) volatile> { typedef T class_type; typedef R return_type; typedef typelist<Args...> arglist; enum { arg_count = sizeof...(Args) }; template<unsigned int N> struct arg { typedef typename at<N, arglist>::type type; }; }; template <typename R, typename T, typename... Args> struct function_traits<R (T::*)(Args...) const volatile> { typedef T class_type; typedef R return_type; typedef typelist<Args...> arglist; enum { arg_count = sizeof...(Args) }; template<unsigned int N> struct arg { typedef typename at<N, arglist>::type type; }; };