访问Lambda之外的捕获变量

时间:2019-05-07 20:31:52

标签: c++

是否可以在lambda代码本身之外访问lambda的捕获值。

template <typename F>
void bar(const F& f)
{
    auto d = f.x;
}

int main()
{
    int x;
    bar([&]{
        do_something(x);
    });
}

2 个答案:

答案 0 :(得分:2)

这是不可能的。 Lambda是一个黑匣子。

选项1:使用返回值

如果只需要一个捕获的变量,并且如果lambda最初应该为空,则只需返回此值。

template <typename F>
void bar(const F& f)
{
    auto d = f();
}
int main()
{
    int x;
    bar([&]{
        auto y=x;  // in case do_something would change x
        do_something(x);
        return y; 
    });
}

选项2:使用多个返回值

如果您已经需要返回值,则可以使用sam方法,但可以使用一对或元组一次返回多个值:

template <typename F>
void bar(const F& f)
{
    auto d = f();
    cout << d.first<<endl;  
}
int main()
{
    int x;
    bar([&]{
        auto y=x; 
        do_something(x);
        return make_pair(y, 0); // first is parameter, second real return
    });
}

选项3:使用可调用项

嗯,它不再是lambda了。但是,如果您需要访问一些更复杂的函数的参数,则可以使用可调用对象。可调用的是普通的类或结构。然后,它可以传达您想要的任何参数,但是您需要定义它们并在可调用对象的构造函数中预见它们:

template <typename F>
void bar(const F& f)
{
    auto d = f.x;
    f();
}
int main()
{
    struct Tmp {  // I won't need this callable elsewhere... 
        int &x; 
        Tmp (int& x) : x(x) {}
        void operator() () const {
           do_something(x);
        }
    };

    int x;
    Tmp t(x); 
    bar(t);
}

在此示例中,我使用了一个本地类定义,以免用扔掉的结构污染名称空间。

Demo

您可以通过将lambda作为构造函数的参数来提供此方法与lambda结合,捕获大量变量,并使用可调用成员来传达您只能在bar()中使用的少数几个。

其他备注

请注意按引用捕获(当捕获的变量可能已死亡时,请不要使用lambda。

如果需要访问lambda的命名参数,则设计中可能存在问题。 Lambda不能传递捕获的变量。因此,如果您有此需要,有可能可赎回债券是一个更好的选择。

答案 1 :(得分:0)

  

是否可以在lambda代码本身之外访问lambda的捕获值

是的,是的,但是不是通过lambda的:不是通过某种方式公开[&] lambda捕获的所有本地名称听起来很讨厌。

这些变量在绑定到lambda之前已经具有名称,您仍然可以照常使用这些名称。

编写具有自己的名称和语义的函子是获得所需行为的唯一方法。如果您不想显式命名每个捕获的变量,则可以使用带有std::apply的元组(以及常规的元组字段访问)。