2016-04-26 17 views
3

这可能是一个概念性问题。我正在执行以lambda作为参数的功能。但是,我无法理解lambda的确切类型。例如:适用于拉姆达封闭移动

auto T = []() { printf("hello world\n"); }; 
auto F = move(T); 
T(); // print "hello world" 
F(); // print "hello world" 

我对T调用move后认为,中T内容消失。换句话说,我希望以下行为:

function<void> T = []() { printf("hello world\n");}; 
auto F = move(F); 
F(); // print "hello world" 
T(); // throw error 

回到原来的问题,什么是合格/于function<void()>类成员分配lambda的最佳做法?我看到很多不同的答案,一些使用const function<void()>&和其他人则建议模板F&&

struct Foo { 

    function<void()> f; 

    // Option 1: 
    void set_f(const function<void()>& in) {f=in;} 

    // Option 2: template 
    template <typename F> 
    void set_f(F&& in) { // what to write here??? } 
} 

是这两个选项一般足以捕捉大多数输入类型?

回答

6

你似乎对编译器用lambda表达式做了什么基本的误解。 Lambda表达式被转换为具有唯一名称的函子。当你调用lambda时,你只需调用函子的operator()即可。

所以在你的第一个例子中,拉姆达会造成这样的

struct __uniquely_named_lambda 
{ 
    void operator()() const 
    { 
     printf("hello world\n"); 
    } 
}; 

如果拉姆达被存储任何状态,那么move从中荷兰国际集团将移动状态,但你的拉姆达是无状态的,所以move做没有;你不能去掉operator()的身体并将它移动到别处。

例如,这些语句会产生输出4 0 4

std::string s{"Test"}; 
auto T = [s]() { std::cout << s.size() << ' '; }; // make a copy of s 
T(); 
auto F = std::move(T); 
T(); 
F(); 

Live demo


std::function是一个容器,可以接受指定的签名匹配任何调用,和你的拉姆达是一个这样的可调用。当您move,std::function时,您正在将其存储的可调用目标移动到目标中。试图在原始上调用目标将会抛出bad_function_call,这与lambda的move有很大不同。


我想你写set_f成员函数作为

template <typename F> 
void set_f(F&& in) 
{ 
    f = std::forward<F>(in); 
} 

在你的例子F是转发引用,这意味着它就能接受调用者传递要么左值右值或。然后分配将复制分配或移动分配参数。

+0

会'f = std :: move(in);'也可以吗? –

+1

@dau_sama这将工作,因为'f'会被分配参数,但它可能不会做调用者的期望。如果你用''std :: function'的非''const'左值引用调用'set_f',它仍然会'移动'参数,这可能不是你想要的。如果你想总是“移动”,你应该改用'F'作为值。 – Praetorian