2012-03-12 79 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