2013-03-28 81 views
14

我看到std::async規定如下:result_of <F(Args...>和decltype <f(args...)>有什麼區別?

template <class F, class... Args>     // copied out of the standard 
future<typename result_of<F(Args...)>::type> 
async(F&& f, Args&&... args); 

我預期它聲明如下:

template <class F, class... Args> 
auto async(F&& f, Args&&... args) -> 
    future<decltype(forward<F>(f)(forward<Args>(args)...)>; 

請問這是等價的,或者是有一些方式,其中使用result_of比使用decltype更可取? (據我所知,result_of適用於類型,而decltype適用於表達式。)

+0

是否用'result_of'指定_或_implemented_?因爲這可能只是實現它的傢伙的心血來潮,或者它可能已經在'decltype'之前實現到目標編譯器。在Apple的libC++中,它既不使用。 – zneak 2013-03-28 04:03:48

+0

@zneak:我展示的聲明被複製出標準,所以'std :: async'是通過'result_of'指定的。實現可以做任何他們喜歡的事情,只要它們提供的行爲與指定的行爲相同即可。 – KnowItAllWannabe 2013-03-28 06:03:03

+0

只要知道'std :: result_of'語法有一些[不幸的含義](http://stackoverflow.com/a/15489789/500104)。 – Xeo 2013-03-28 07:44:15

回答

11

您的版本不適用於例如指向成員。再仔細,但仍然沒有確切的版本是:

template <class F, class... Args> 
auto async(F&& f, Args&&... args) 
-> future<decltype(ref(f)(forward<Args>(args)...))>; 

std::result_of剩下的唯一的區別是,這個轉發仿函數作爲一個左值(一個問題,你的版本也萬股)。換句話說,這種呼叫的結果(通過std::reference_wrapper<F>)是typename std::result_of<F&(Args...)>::type

這是一個尷尬的局面,其中標準庫的幾個組成部分(僅舉幾例,除了那些我們剛剛見證:std::threadstd::bindstd::function)在一個難以捉摸的援引術語規定(F, a0,a1,...,aN)僞表達式,它不完全等同於f(a0, a1, ... aN)。由於std::result_of是其中一個組件,並且實際上用於計算結果類型INVOKE,這就是您注意到的差異。

因爲沒有std::invokestd::result_of類型特徵串聯,我認爲後者僅用於描述例如當您的代碼調用它們時,相關標準庫組件的返回類型。如果你想要一個簡潔而自我記錄的寫作方式,例如返回類型(一個非常有價值的目標是爲了便於閱讀,比噴灌decltype無處不在),那麼我建議你寫你自己的別名:

template<typename F, typename... A> 
using ResultOf = decltype(std::declval<F>()(std::declval<A>()...)); 

(如果你想別名被用作ResultOf<F(A...)>代替ResultOf<F, A...>那麼你需要一些機器來模式匹配功能簽名。)

這個別名的一個額外的好處是它是SFINAE友好的,不像std::result_of。是的,這是它的另一個缺陷。 (公平地說,雖然已經對即將推出的標準進行了修改,但實施已經進行了相應的修改。)

如果您使用這樣的特性,您可以使用指針,因爲您可以修改指向成​​員的指針std::mem_fn

+0

我修改了原始代碼,以便'decltype'版本將'std :: forward'應用於'f',因此推測可以消除所有函數對象都在左值處理的問題。感謝您指出了這一點。 – KnowItAllWannabe 2013-03-30 04:48:31

+0

我接受了這個答案,因爲我認爲'decltype'版本不支持指向成員的觀察是很重要的。 – KnowItAllWannabe 2013-04-01 17:32:48

5

從功能上看,沒有任何區別。然而,decltype版本使用尾隨返回類型,這是從編程的角度的一個區別。

在C++ 11中,std::result_of不是絕對必要的,可以使用decltype代替,就像您使用的方式一樣。但std::result_of向後兼容第三方庫(較舊的),如具有result_of的Boost。雖然我沒有看到太多優勢。

就個人而言,我更喜歡使用decltype因爲它是更強大,並與任何實體的作品,而作品result_of只調用實體。所以如果我使用decltype,我可以在任何地方使用它。但與result_of,我不得不偶爾切換到decltype(即,當實體是而不是可調用)。請參閱this at github,我已使用decltype作爲所有功能的返回類型。

+0

另一個編程區別是'decltype'版本需要使用'forward',而'return_of'版本顯然不需要。 – KnowItAllWannabe 2013-03-28 03:39:17

+0

@KnowItAllWannabe:正如你已經注意到自己(在問題中),'std :: result_of'與* types *一起工作,所以沒有什麼可以轉發。 – Nawaz 2013-03-28 03:40:46

+0

我想你的意思是'std :: result_of',你寫了'std :: result_type'。 – KnowItAllWannabe 2013-03-28 03:48:31

5

您的問題已經有所不同了:「我知道result_of適用於類型,而decltype適用於表達式。」

它們都提供相同的功能(std::result_of甚至在decltype時下方面實現的),併爲您的例如的差異主要是不存在的,因爲你已經有了必需的變量構建表達式。

也就是說,差異歸結爲當你只有類型的語法糖。試想一下:

typename std::result_of< F(A, B, C) >::type 

decltype(std::declval<F>()(std::declval<A>(), std::declval<B>(), std::declval<C>()) 

而只記得std::result_of是在這些情況下的一個選項。

請注意,有些情況下decltype可以以std::result_of不能使用的方式使用。就我所知,考慮decltype(a + b),您無法找到F來創建等效的std::result_of< F(A, B) >

+1

你真的想在每個模板參數而不是'std :: forward'上使用'std :: declval'嗎? – KnowItAllWannabe 2013-03-29 17:48:26

+0

如果您只有**類型**,請重新閱讀答案。沒有這種類型的變量,你不能使用'std :: forward',因爲它需要一個參數。 – 2013-03-29 21:01:33

+1

Downvoter:爲什麼? – 2013-03-29 21:06:09

相關問題