如何在Lambda本身中获取C ++ Lambda函数的地址?

Dak*_*ksh 52 c++ lambda c++11 c++14 c++17

我试图弄清楚如何在自身中获取lambda函数的地址。这是一个示例代码:

[]() {
    std::cout << "Address of this lambda function is => " << ????
}();
Run Code Online (Sandbox Code Playgroud)

我知道我可以在变量中捕获lambda并打印地址,但是我想在执行此匿名函数时就地执行此操作。

有没有更简单的方法?

Yak*_*ont 51

无法直接获取lambda中的lambda对象的地址。

现在,碰巧这经常很有用。最常见的用途是为了递归。

这些y_combinator语言来自您在定义之前无法谈论自己的语言。它可以很容易地在

template<class F>
struct y_combinator {
  F f;
  template<class...Args>
  decltype(auto) operator()(Args&&...args) const {
    return f( f, std::forward<Args>(args)... );
  }
  template<class...Args>
  decltype(auto) operator()(Args&&...args) {
    return f( f, std::forward<Args>(args)... );
  }
};
Run Code Online (Sandbox Code Playgroud)

现在您可以执行以下操作:

y_combinator{ [](auto& self) {
  std::cout<<"Address of this lambda function is => "<< &self;
} }();
Run Code Online (Sandbox Code Playgroud)

其变化形式可以包括:

template<class F>
struct y_combinator {
  F f;
  template<class...Args>
  decltype(auto) operator()(Args&&...args) const {
    return f( *this, std::forward<Args>(args)... );
  }
  template<class...Args>
  decltype(auto) operator()(Args&&...args) {
    return f( *this, std::forward<Args>(args)... );
  }
};
Run Code Online (Sandbox Code Playgroud)

在这里self通过可以称为不传递self作为第一个参数。

第二个匹配我相信的实数y组合器(又名定点组合器)。您想要哪个取决于“ lambda地址”的含义。

  • 我觉得如果您使用C ++进行此操作,就应该被逮捕 (13认同)
  • 哇,Y组合器很难用Lisp / Javascript / Python之类的动态类型语言来处理您的问题。我从没想过我会在C ++中看到它。 (3认同)
  • @MSalters不确定。如果`F`不是标准布局,则`y_combinator`不是,因此没有提供合理的保证。 (3认同)
  • @carto最重要的答案只有在您的lambda处于范围内时才起作用,并且您不介意类型擦除开销。第三个答案是y组合器。第二个答案是手动合成器。 (2认同)
  • @kaz C ++ 17功能。在11/14中,您将编写一个make函数,该函数将对F进行分界。在17中,您可以推断出模板名称(有时还可以推断出指南) (2认同)

Max*_*kin 33

这不是直接可能的。

但是,lambda捕获是类,对象的地址与其第一个成员的地址一致。因此,如果按值捕获一个对象作为第一个捕获,则第一个捕获的地址对应于lambda对象的地址:

int main() {
    int i = 0;
    auto f = [i]() { printf("%p\n", &i); };
    f();
    printf("%p\n", &f);
}
Run Code Online (Sandbox Code Playgroud)

输出:

0x7ffe8b80d820
0x7ffe8b80d820
Run Code Online (Sandbox Code Playgroud)

另外,您可以创建一个装饰器设计模式 lambda,将对lambda捕获的引用传递到其调用运算符中:

template<class F>
auto decorate(F f) {
    return [f](auto&&... args) mutable {
        f(f, std::forward<decltype(args)>(args)...);
    };
}

int main() {
    auto f = decorate([](auto& that) { printf("%p\n", &that); });
    f();
}
Run Code Online (Sandbox Code Playgroud)

  • @n。'代词'。不,这是一个不可移植的解决方案。捕获实现可能会从最大到最小对成员进行排序以最小化填充,标准明确允许这样做。 (34认同)
  • “对象的地址与其第一个成员的地址一致”是在某个位置指定了捕获顺序,还是没有不可见的成员? (15认同)
  • 重新,“这是一个不可移植的解决方案。” 那是_undefined behavior._的别称。 (12认同)
  • 我认为它是*未指定的*,根据第8.1.5.2节第15节:*在评估lambda表达式时,将使用通过复制捕获的实体直接初始化结果闭包中的每个对应的非静态数据成员对象,并且与初始化捕获相对应的非静态数据成员如相应的初始化程序(...)所示进行初始化。(对于数组成员,数组元素以递增的下标顺序直接初始化。)这些初始化以声明非静态数据成员的(**未指定**)顺序执行。 (4认同)

ruo*_*ola 25

解决此问题的一种方法是将lambda替换为手写仿函数类。这实际上也是lambda的本质。

然后this,即使没有将函子分配给变量,也可以通过获得地址:

#include <iostream>

class Functor
{
public:
    void operator()() {
        std::cout << "Address of this functor is => " << this;
    }
};

int main()
{
    Functor()();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

#include <iostream>

class Functor
{
public:
    void operator()() {
        std::cout << "Address of this functor is => " << this;
    }
};

int main()
{
    Functor()();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这样做的好处是,它是100%可移植的,并且非常易于推理和理解。

  • 函子甚至可以像lambda一样声明:`struct {void operator()(){std :: cout &lt;&lt;“此函子的地址为=&gt;”“ &lt;&lt;此&lt;&lt;'\ n'; }} f;` (9认同)