2015-07-10 36 views
1
template<typename F,typename...X> 
using Result_of = typename result_of<F(X...)>::type; 

int ff(int){return 2;} 
typedef bool(*PF)(int); 
auto fx = [](char ch){return tolower(ch);}; 
Result_of<decltype(&ff)()> r1 = 7; 
Result_of<PF(int)> r2 = 2; 
Result_of<decltype(fx)(char)> r5 = "a"; 

當我用gcc編譯,我得到以下錯誤:如何寫的result_of一個輔助型的C++ 11

main.cpp: In substitution of 'template<class F, class ... X> using Result_of = typename std::result_of<_Functor(_ArgTypes ...)>::type [with F = int (*())(int); X = {}]': 
main.cpp:17:30: required from here 
main.cpp:6:57: error: function returning a function 
using Result_of = typename std::result_of<F(X...)>::type; 
                 ^

爲什麼會出現這種錯誤,以及如何解決呢?

回答

2

有幾件事情錯了這條線:

Result_of<decltype(&ff)()> r1 = 7; 

首先,Result_of需要一個功能類型和參數列表,以逗號分隔。你不是這樣提供的。所以它將F解釋爲(int)(*)(int)(),它將是一個函數指針,它將返回一個返回int的函數int。但在C++中有一個函數返回一個函數是非法的,因此是錯誤。

其次,ff需要一個int,不是沒有。最後,ff衰減到指向函數,並且您需要實際的函數。正確的表達應該是:

Result_of<decltype(*ff), int> r1 = 7; 

同樣,接下來需要爲:

Result_of<PF, int> r2 = 2; 
Result_of<decltype(fx), char> r5 = 'a'; // fx returns an int, so you 
             // can't assign a const char* to it 
+0

你絕對確保OP想要使用逗號分隔的版本? – Yakk

+0

@Yakk我不知道OP還可以想要什麼? – Barry

+1

'模板使用Result_of = typename std :: result_of :: type;'是我的猜測,因爲這使得他的用例按原樣編譯。 – Yakk

2

簡短的回答是:

template<class Sig> 
using Result_of = typename std::result_of<Sig>::type; 

會讓你的用例的 「工作」。有些會因編碼錯誤或類型不匹配而無法編譯。

但是,這不是最好的方法。

C++ 11編譯器並不都實現最佳實踐版本result_of:即SFINAE友好版本。如果您正在撰寫幫手,我會以最佳做法風格進行操作。

首先,別名做decltype評價:

template<class F, class...Args> 
using invoke_result = decltype(std::declval<F>()(std::declval<Args>()...)); 

下,一些元編程樣板我覺得有用:

namespace details { 
    template<class...>struct voider{using type=void;}; 
    template<class...Ts>using void_t=typename voider<Ts...>::type; 

    template<template<class...>class Z, class, class...Ts> 
    struct can_apply:std::false_type{}; 
    template<template<class...>class Z, class...Ts> 
    struct can_apply<Z, void_t<Z<Ts...>>, Ts...>:std::true_type{}; 
} 
template<template<class...>class Z, class...Ts> 
using can_apply=details::can_apply<Z,void,Ts...>; 

can_apply< template, args... >回答這個問題:「正在申請的ARGS ...到模板有效?「。這非常有用。

正如我們在C++ 11的土地,一個enable_if_t別名使得代碼看起來更漂亮:

template<bool b, class T=void> 
using enable_if_t=typename std::enable_if<b,T>::type; 

我們現在可以開始在result_of_t別名工作:

namespace details { 
    template<class Sig,class=void> 
    struct result_of {}; 
    template<class F, class...Args> 
    struct result_of< 
    F(Args...), 
    enable_if_t<can_apply<invoke_result, F, Args...>> 
    > { 
    using type=invoke_result<F,Args...>; 
    }; 
} 
template<class Sig> 
using result_of_t = typename details::result_of<Sig>::type; 

,我們做。

這會生成一個名爲result_of_t的SFINAE友好型別名,它在任何兼容的C++ 11編譯器中都可以像高質量的C++ 14 std::result_of_t一樣工作。它在MSVC上不能很好地工作,但那是因爲MSVC2015仍然沒有充分實現C++ 11。

所有的例子都應該使用result_of_t代替Result_of,或者因爲它們無效而失敗。

int ff(int){return 2;} 
typedef bool(*PF)(int); 
auto fx = [](char ch){return tolower(ch);}; 

result_of_t<decltype(&ff)()> r1 = 7; 

失敗,因爲你必須通過一個intff。這會工作:

result_of_t<decltype(&ff)(int)> r1 = 7; 

result_of_t<PF(int)> r2 = 2; 

這個分配2bool。所以它...的作品。

result_of_t<decltype(fx)(char)> r5 = "a"; 

這個分配"a"int,這可能不是你想要的。 (tolower在C/C++中返回int)。

我們可以通過解決這個問題:

auto fx = [](char ch)->char{return tolower(ch);}; 
result_of_t<decltype(fx)(char)> r5 = 'a'; 
+1

那麼,幾乎編譯。仍然需要爲'decltype(&ff)()'添加'int',並且仍然不能將''a''賦值給'int'。 – Barry

+0

@Barry s/compile/work /,對於包括「不,沒有意義」的工作價值。 – Yakk