应用移动lambda闭包

Jes*_*Jes 3 c++ lambda c++11

这可能是一个概念性问题.我正在实现lambda作为参数的函数.但是,我无法理解a的确切类型lambda.例如:

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

我打完电话后想到moveT,内容T消失了.换句话说,我期望以下行为:

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

回到最初的问题,传递/分配lambda给一个类成员的最佳做法是function<void()>什么?我看到了许多不同的答案,一些使用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??? }  
}
Run Code Online (Sandbox Code Playgroud)

这两个选项是否足以捕获大多数输入类型?

Pra*_*ian 6

您似乎对编译器对lambda表达式的作用有一个基本的误解.Lambda表达式转换为具有唯一名称的仿函数.当你调用lambda时,你只需要调用operator()functor.

所以你的第一个例子中的lambda将创建这样的东西

struct __uniquely_named_lambda
{
    void operator()() const
    {
        printf("hello world\n");
    }
};
Run Code Online (Sandbox Code Playgroud)

如果这个lambda存储任何状态,那么move从它移动将移动状态,但你的lambda是无状态的,所以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();
Run Code Online (Sandbox Code Playgroud)

现场演示


std::function是一个容器,可以接受任何与指定签名匹配的可调用对象,并且您的lambda是一个可调用的.当你movestd::function,你的移动目标可赎回它存储到目的地.尝试调用原始目标然后抛出bad_function_call,这move与lambda 非常不同.


我会把你的set_f成员函数写成

template <typename F>
void set_f(F&& in)
{
    f = std::forward<F>(in);
}
Run Code Online (Sandbox Code Playgroud)

F在您的示例中是转发引用,这意味着它将能够接受调用者传递的左值或右值.然后,赋值将复制赋值或移动赋值参数.