簡體   English   中英

我應該總是使用`T &&`而不是`const T&`或`T&`來綁定回調函數?

[英]Should I always use `T&&` instead of `const T&` or `T&` to bind to a callback function?

template <typename T>
void myFunction(..., T && callback) {
    ...
    callback(...);
    ...
}

是否最好使用T &&不是T&const T&

或者甚至簡單地用T來傳遞值而不是通過引用傳遞。

函數或lambdas是否具有左值和右值的概念? 我可以std::move一個函數/ lambdas嗎?

const const T&是否強制該函數無法修改其閉包?

使用轉發引用可能會有所不同,但您必須正確調用回調才能看到它。 對於函數和lambdas來說,如果它們是rvalue或lvalue並不重要,但是如果你有一個仿函數,它可以有所作為

template <typename T>
void myFunction(..., T && callback) {
    callback(...);
}

獲取轉發引用,然后將回調作為左值調用。 如果函數對象作為右值傳遞,並且其調用運算符被定義為,則這可能是錯誤

operator()(...) && { ... }

因為它只能在右值上調用。 為了使您的函數正常工作,您需要將函數名稱包裝在std::forward以便在它傳遞給函數的相同值表達式類別中調用它。 看起來像

template <typename T>
void myFunction(..., T && callback) {
    std::forward<T>(callback)(...); 
    // you should only call this once since callback could move some state into its return value making UB to call it again
}

因此,如果你想獲取rvalues和lvalues,並將運算符稱為rvalue或lvalue,那么應該使用上面的方法,因為它就像在myFunction的調用站點中進行調用一樣。

是否最好使用T &&而不是T&或const T&?

通用引用允許完美轉發,因此它們通常在通用模板函數中更受歡迎。

或者甚至簡單地用T來傳遞值而不是通過引用傳遞。

當您希望獲得所有權時,這通常更可取。

函數或lambdas是否具有左值和右值的概念?

是。 每個值表達式都有一個值類別。

我可以std :: move一個函數/ lambdas嗎?

是。 你可以std::move幾乎任何東西。

另一個問題是是否std::move對象。 另一個問題是物體是否可以移動。 Lambda可移動,除非它們包含不可移動的捕獲。

在OP的例子中:

template <typename T>
void myFunction(..., T && callback) {
    ...
    ...
}

通過T&&將為您提供兩全其美的體驗。 如果我們傳遞r值引用,模板將使用r值引用解析函數,但如果我們傳遞l值引用,則函數將解析為l值。 傳遞callback ,請記住使用std::forward來保留l / r值。

這僅在T是模板化時有效,這不是我們使用類似std :: function的情況。

那么我們在非模板化的例子中傳遞了什么呢。 首先要決定的是在函數退出后是否可以調用callback 如果僅在myFunc的范圍內調用回調,則最好使用l值引用,因為您可以直接調用引用。

但是,如果在myFunc的范圍之后callback ,則使用r值將允許您move callback 這將保存您的副本,但會強制您保證在傳遞給myFunc后無法在其他任何地方使用回調。

在C ++函數中(不要與std::function混淆)本質上只是指針。 您可以移動指針,盡管它與復制指針相同。

引擎蓋下的Lambdas只是或多或少的常規struct (或class es,它是相同的)實現operator()並可能存儲一些狀態(如果你的lambda捕獲它)。 因此, move將起到與常規結構相同的作用。

類似地,可能存在move-only lambdas(因為它們在其狀態中具有僅移動值)。 所以有時,如果你想接受這樣的lambda,你需要通過&&

但是,在某些情況下,您需要一個副本(例如,如果您想在線程中執行函數)。

您可能想要選擇T (帶有可選的std::ref )或T&&並選擇其中一個。

如果你想讓調用者知道myFunction不會修改callback ,那么T const&有效。 如果callback可能是有狀態的,它就不起作用。 當然,如果callbackoperator()被標記為const (或callback是一個非mutable lambda),那么myFunction將不會修改callback 從本質上講,任何調用myFunction都可以為自己提供constness保證。

T&工作,如果你想myFunction被允許參加一個有狀態的仿函數。 缺點是T&不能綁定到右值(例如myFunction([&](Type arg){ /* whatever */ }) )。

T對有狀態和無狀態函子都有好處,它適用於rvalues(例如lambdas)和lvalues。 如果調用myFunction希望更改callback的狀態在myFunction之外是可觀察的(例如callback不僅僅是operator() ),他們可以使用std::ref 這就是C ++標准庫的用武之地。

T&&同樣是通用的(它可以處理rvalues和/或有狀態函子),但是它不需要std::ref來對myFunction外部的callback進行更改。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM