我有我的代碼庫中的各種功能,它需要一個通用的可調用對象,並在調用它之前將它傳遞給一系列嵌套的lambdas。例如:在嵌套lambdas中捕獲泛型可調用對象 - 總是轉發?
template <typename TF>
void interface(TF&& f)
{
nested0([/*...*/]()
{
nested1([/*...*/](auto& x)
{
nested2([&x, /*...*/]()
{
f(x);
});
});
});
}
注意interface
由轉發參考(以前稱爲通用參考)服用TF
類型的一個可調用對象。可調用對象通常是一個帶有各種捕獲變量的lambda表達式,既有值,也有引用。
在保持正確性的同時捕獲嵌套lambda中的f
的最佳方式(就性能而言)是什麼?
我能想到的三個選項:
捕獲
f
的副本。nested0([f]() { nested1([f](auto& x) { nested2([&x, f]() { f(x); }); }); });
可能會導致不必要的副本,如果拍攝對象物
mutable
它可能會導致不正確的行爲。捕獲
f
作爲參考。nested0([&f]() { nested1([&f](auto& x) { nested2([&x, &f]() { f(x); }); }); });
似乎是合理的,但可能會造成問題,如果任何嵌套的lambda表達式執行會超越的
f
所有者的動作。想象一下,如果nested2
的身體在一個單獨的線程中執行 -f
可能已經超出範圍。使lambdas
mutable
和捕捉完美轉發。#define FWD(...) std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__) nested0([f = FWD(f)]() mutable { nested1([f = FWD(f)](auto& x) mutable { nested2([&x, f = FWD(f)]() mutable { f(x); }); }); });
的lambda表達式必須
mutable
,因爲我們可能從拉姆達到另一個移動f
。這種方法似乎可以避免不必要的副本,並且如果它需要超過原始調用者,則可以正確地移動可調用對象。
選項3總是最好的,還是它有任何潛在的缺點? ...或者根本沒有「最佳和正確」的方式(需要關於可調用對象的知識)?
爲什麼在內部lambda表達式中使用forward時,'f'不再引用函數參數? –
@PiotrSkotnicki:因爲我仍然需要從「當前」lambda中捕獲外部lambda的'f'。如果'interface'的'f'被移動到第一個lambda中,我想將第一個lambda的'f'移到第二個中,等等。 –
我的意思是,這相當於在內部lambda表達式中移動 –