簡體   English   中英

綁定lambda的速度(通過std :: function)與functor struct的operator()

[英]Speed of bound lambda (via std::function) vs operator() of functor struct

auto lam = [](int a, int b, int c) { return a < b && b < c; };

struct functor {
  int a;
  int b;
  bool operator()(int n) const { return a < n && n < b; }
};

在第一版中,我們

std::vector<std::function<bool (int)>> lamvals;
// get parameters and for each
lamvals.emplace_back(std::bind(lam, a, std::placeholders::_1, b));

替代方案是

std::vector<functor> lamvals;
// get parameters and for each
lamvals.emplace_back(functor{a, b});

在這兩種情況下,我們都有一個簡單的迭代

    return std::any_of(lamvals.cbegin(), lamvals.cend(),
            [n](const decltype(lamvals)::value_type & t){return t(n);});

我看到速度差為3:1,綁定的lambda更慢。 仿函數幾乎與存儲整數對和硬編碼測試一樣快。 顯然,硬編碼對於生產代碼沒那么有用,因為會有幾個功能在起作用,而不僅僅是在它們之間。 但是,我可以選擇許多仿函數或許多lambdas。 后者是更少的代碼行,看起來更干凈,但我認為我不能承受這種速度差異; 此代碼處於關鍵循環中。

我正在尋找加速建議。

兩種情況之間的區別基本上是使用仿函數,編譯器確切地知道在編譯時將調用什么,因此可以內聯函數調用。 有趣的是,Lambdas也有一種獨特的類型。 這意味着,當你使用lambda時,在編譯類型(因為編譯器必須知道所有類型),被調用的函數已經知道,所以可以進行內聯。 另一方面,函數指針僅基於其簽名的類型。 必須知道簽名,以便可以適當地調用它並從中返回,但除了編譯器所涉及的功能指針可以在運行時指向任何內容之外。 關於std :: function也是如此。

將lambda包裝在std :: function中時,從編譯器的角度刪除lambda的類型。 如果這聽起來很奇怪/不可能,那就這樣想吧:因為固定類型的std :: function可以用相同的簽名包裝任何可調用的,所以編譯器無法知道其他一些指令不會單獨發生並且改變什么是std :: function包裝。

這個鏈接, http://goo.gl/60QFjH ,顯示我的意思(順便說一下,Godbolt頁面非常方便,我建議熟悉它)。 我在這里寫了三個類似於你的例子。 第一個使用std :: function包裝lambda,第二個使用funl,第三個是使用decltype的裸lambda(unwrapped)。 您可以查看右側的程序集,看到后兩者都內聯,但不是第一個。

我的猜測是你可以使用lambdas做同樣的事情。 您可以使用a和b的lambdas進行基於值的捕獲,而不是綁定。 每次將lambda推回向量時,適當地修改a和b,然后瞧。

從風格上來說,我實際上強烈認為你應該使用結構。 發生了什么事情要清楚得多。 事實上,你似乎想要在一個地方捕獲a和b,並在另一個地方測試c,這意味着你的代碼中不僅僅在一個地方使用它。 為了換取類似的2行代碼,您可以獲得更易讀,更易於調試和更具可擴展性的內容。

暫無
暫無

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

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