2017-03-05 65 views
2

我一直在尋找在std::function執行和它的呼叫operator()在std :: function運算符()和std :: forward中發生了什麼?

template<typename Ret, typename... ArgTypes> 
Ret function< Ret (ArgTypes...)>::operator()(ArgTypes...args) const 
{ 
    // some stuff 
    return invoker(functor, std::forward<ArgTypes>(args)...); 
} 

我特別想知道,爲什麼它使用std::forward這裏?這是否與完美的轉發有關? 因爲完美的轉發只能在operator()是一個帶可變參數模板聲明的模板template<typename... Args>(它不是,聲明是std :: function的部分特化)。 這裏使用std :: forward的意圖是什麼?我很困惑 :-)?

+3

'*它不是*'不是嗎?當然看起來對我來說。 – Biffen

+0

該聲明是std :: function和templ的完全專業化。參數'Ret,ArgTypes'已經修復 – Gabriel

+3

看起來像一個類模板的部分專業化的成員函數給我。我不確定你在哪裏看到完整的專業化(完全專業化會有空的模板參數列表)。 – 2017-03-05 15:51:47

回答

3

你是對的,這不是你典型的「完美轉發」場景。一個簡單的例子可以幫助說明動機。假設類型A與儀表化的構造和析構函數:

#include "A.h" 
#include <functional> 
#include <iostream> 

int 
main() 
{ 
    A a1{1}; 
    A a2{2}; 
    std::function<void(A, A&)> f{[](A x, A& y){}}; 
    f(a1, a2); 
} 

這將輸出:

A(int state): 1 
A(int state): 2 
A(A const& a): 1 
A(A&& a): 1 
~A(1) 
~A(-1) 
~A(2) 
~A(1) 

說明:

a1a2構造堆棧上。然後,當傳入function調用者時,首先複製a1以綁定到第一個按值參數,然後在a1上調用std::forward<A>,其中從by-value參數移動到lambda中。

相反,a2不需要被複制到綁定到functionA&參數,然後std::forward<A&>(a2)被調用,它轉發a2作爲左值代替右值,並且該結合拉姆達的A&參數。

然後事情被破壞。 ~A(-1)表示AA的移動構建狀態下銷燬。

總之,即使ArgTypes未按照通常的完美轉發方式推導出來,我們仍然希望將值ArgTypes轉換爲右值,並將引用ArgTypes作爲左值。所以std::forward只是恰好做到了我們在這裏想要的。

+0

@加布裏埃爾:對不起,我不明白後續問題。你可以再詳細一點嗎? –

+0

@Gabriel:'std :: function' **是按照我上面描述的**制定的。如果這就是你的問題中的「那個」,那麼標準已經是這樣了。對不起,如果我很密集。目前我已經睡了很多小時了。 –

0

std::forward只是將rvalue引用附加到該類型,因此將參考摺疊規則考慮在內,它有效地傳遞參考參數並移動對象參數。

1

我覺得你很困惑這裏很多事情。

首先,完美轉發與可變參數模板無關。你可以創建一個具有功能,它有一個參數,並將它轉發給被包裝的對象的包裝類:

template<typename T> 
struct Wrapper { 
    template<typename Arg> 
    decltype(auto) test(Arg&& arg) { 
     return t.test(std::forward<Arg>(arg)); 
    } 

    T t; 
}; 

注意這裏使用完美轉發沒有任何可變參數模板。如果t.test僅需要移動類型作爲參數,則不可能在沒有forward<Arg>(arg)的情況下調用它。


第二件事發生在這裏是不被後面&&參數。將&&添加到ArgTypes將是一個錯誤,並會使某些情況下無法編譯。考慮這個簡單的例子:

std::function<void(int)> f; 
int i = 0; 
f(i); 

這將編譯失敗。如果將&&添加到ArgTypes,則每個不參考的參數(例如int)都將成爲呼叫操作員的右值參考(在本例中爲int&&)。由於所有參數類型已在std::function參數列表中正確限定,因此您希望在調用操作符中接收的參數類型正是這些類型,而不是轉換的類型。

爲什麼你需要std::forward如果你不使用&&?因爲即使您不需要推斷值類別,您仍然不需要將所有參數複製到包含的函數中。如果其中一個std::function的參數是int&,您不想移動它。但如果其中一個參數是std::unique_ptr<int>,則必須移動它!這正是std::forward的目的。只移動應該移動的內容。

相關問題