2012-03-12 81 views
6

是否可以約束作爲參數給定的lambda捕獲類型?
例如,是否可以只採取不通過引用捕獲任何東西的lambda表達式?C++ lambda捕獲約束條件

template <typename F> 
void f(const F& lambda) // F must be a lambda that do not capture by ref 
{ 
    ::: 
} 
+2

當閉包對象碰到你的函數時,它已經被構造了,你不知道它的內部是什麼,因爲它們是私有的。但是,如果你想知道,lambda當然不能捕獲任何*事後*,尤其是* *你的*函數'f'中沒有任何東西。 – 2012-03-12 13:55:32

+5

這樣做毫無意義,因爲按值捕獲指針與捕獲參考一樣危險。 – 2012-03-12 14:01:34

+0

@BenVoigt沒錯。 – log0 2012-03-12 14:02:40

回答

5

MSalters注意到「非捕獲的lambda可以轉換爲函數指針。」這是什麼意思? lambda對象將匹配指向函數參數類型的指針。

將lambda類型轉換爲指向函數的指令是非常棘手的。這是我嘗試遵循一個合規的實現。這有點駭人聽聞。

#include <type_traits> 

template< typename fn > 
struct ptmf_to_pf; 

template< typename r, typename c, typename ... a > 
struct ptmf_to_pf< r (c::*) (a ...) const > 
    { typedef r (* type)(a ...); }; 

// Use SFINAE to hide function if lambda is not convertible to function ptr. 
// Only check that the conversion is legal, it never actually occurs. 

template< typename lambda > 
typename std::enable_if< std::is_constructible< 
     typename ptmf_to_pf< decltype(&lambda::operator()) >::type, 
     lambda >::value >::type 
f(lambda arg) { 
    arg("hello "); 
    arg("world\n"); 
} 

#include <iostream> 

int main() { 
int x = 3; 
    f([](char const *s){ std::cout << s; }); // OK 
    f([=](char const *s){ std::cout << s; }); // OK 
    f([=](char const *s){ std::cout << s << x; }); // error 
} 

這不會接受函數指針作爲直接參數,因爲模板參數需要解析爲函子。您可以通過爲ptmf_to_pf提供專門接受指向函數類型的指針來實現此目的。

另外,如演示所示,它不會接受通過值來捕獲任何內容的lambda表達式,也可以通過引用來接受它。 C++沒有辦法使限制如此具體。

+0

爲什麼不把lambda作爲函數指針傳遞,然後沒有模板? – perreal 2012-03-15 01:37:08

+1

@perreal:如果你知道所需的函數指針類型,那就這樣做。在一般情況下,這是不知道的。 – Potatoswatter 2012-03-15 02:20:19

5

也許你誤解lambda表達式的捕捉行爲:一個閉包對象就像是一個仿函數對象闡明,所以

struct Fun 
{ 
    Fun (int & a) : n(a) { } 
    int operator()(...) { ... } 
private: 
    int & n; 
}; 

int q; 
Fun f(q); 
f(...); 

是完全一樣的

int q; 
auto f = [&q](...) -> int { ... }; 
f(...); 

構建閉包對象後,所有捕獲和綁定都會完成並永久鎖定到對象中。

如果您現在將對象傳遞到其他位置,如call_me(f),則收件人函數與函子或閉包對象的構造沒有關係。

+1

這是真的,但lambda的編譯器生成類型包含捕獲發生的所有細節。人們可以很容易地想象一個元數據系統,它允許自省這種類型來查看是否有任何引用成員(或者構造函數是否有任何引用參數)。 – 2012-03-12 14:06:31

+0

@BenVoigt是的,這可能是仿函數對象的特徵... – log0 2012-03-12 14:07:50

3

間接破解:只有非捕獲的lambda可以轉換爲指向函數的指針。當然,這也涵蓋了很多不屬於lambda的F類型。

+0

允許非lambda函數指針可能是無害的或有益的。+1 – Potatoswatter 2012-03-14 09:20:16