在 lambda 闭包上应用移动

apply move on a lambda closure

本文关键字:应用 移动 闭包 lambda      更新时间:2023-10-16
这可能是

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

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

我以为在T上打电话给move后,T的内容消失了。换句话说,我期望以下行为:

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

回到最初的问题,将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??? }  
}

这两个选项是否足够通用,可以捕获大多数输入类型?

您似乎对编译器使用 lambda 表达式做什么有一个基本的误解。Lambda 表达式将转换为具有唯一名称的函子。当您调用 lambda 时,您只是在调用函子的operator()

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

struct __uniquely_named_lambda
{
    void operator()() const
    {
        printf("hello worldn");
    }
};

如果这个 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();

现场演示


std::function 是一个容器,可以接受与指定签名匹配的任何可调用对象,而您的 lambda 就是这样一种可调用对象。当您move std::function时,您将它存储的可调用目标移动到目标中。尝试在原始目标上调用目标会抛出bad_function_call,这与move lambda 非常不同。


我会把你写set_f成员函数

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

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