[英]Should I use `const T&` instead of `T&&` in my code like stl
[英]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
可能是有狀態的,它就不起作用。 當然,如果callback
的operator()
被標記為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.