簡體   English   中英

如何在 Z945F3FC449288A73B6CZ5F 本身中獲取 C++ lambda function 的地址?

[英]How to get the address of a C++ lambda function within the lambda itself?

我試圖弄清楚如何在其內部獲取 lambda function 的地址。 這是一個示例代碼:

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

我知道我可以在變量中捕獲 lambda 並打印地址,但我想在執行此匿名 function 時就地執行此操作。

有沒有更簡單的方法可以做到這一點?

沒有辦法在 lambda 中直接獲取 lambda object 的地址。

現在,碰巧這通常很有用。 最常見的用途是為了遞歸。

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)... );
  }
};
template<class F>
y_combinator(F)->y_combinator<F>;

現在你可以這樣做:

y_combinator{ [](auto& self)-> void {
  std::cout<<"Address of this lambda function is => "<< &self;
} }();

有一些有用的變化。 我發現特別有用的一種變體是:

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)... );
  }
};

可以調用self傳遞的位置,而無需將self作為第一個參數傳入。

我相信第二個匹配真正的 y 組合器(又名定點組合器)。 您想要哪個取決於您所說的“lambda 地址”。

還有這個精辟的:

template<class R, class...Args>
auto Y = [] (auto f) {
  auto action = [=] (auto action) -> std::function<R(Args...)> {
    return [=] (Args&&... args)->R {
      return f( action(action), std::forward<Args>(args)... );
    };
  };
  return action(action);
};

它返回一個標准 function。


現在,有一個提議——特別是遞歸 lambda真的很容易。

 auto fib = [](auto& this self, int n) { if (n < 2) return n; return self(n-1) + self(n-2); };

(這個提案在標准會議上得到了非常積極的評價)。

這不是直接可能的。

但是,lambda 捕獲的是類,並且 object 的地址與其第一個成員的地址一致。 因此,如果您按值捕獲一個 object 作為第一次捕獲,則第一次捕獲的地址對應於 lambda object 的地址:

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

輸出:

0x7ffe8b80d820
0x7ffe8b80d820

或者,您可以創建一個裝飾器設計模式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();
}

解決此問題的一種方法是用手寫函子 class 替換 lambda。 這也是 lambda 的本質所在。

然后您可以通過this獲取地址,即使沒有將函子分配給變量:

#include <iostream>

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

int main()
{
    Functor()();
    return 0;
}

Output:

 Address of this functor is => 0x7ffd4cd3a4df

這樣做的好處是它是 100% 可移植的,並且非常容易推理和理解。

捕獲 lambda:

std::function<void ()> fn = [&fn]() {
  std::cout << "My lambda is " << &fn << std::endl;
}

下面是一個 promise 版本方法:

#include <future>
#include <cstdio>

int main() {
    std::promise<void *> p;

    auto f = [ready_future = p.get_future()]() mutable {
             printf("%p\n", ready_future.get());
        };

    p.set_value(&f);

    f();
}

這是可能的,但高度取決於平台和編譯器優化。

在我知道的大多數架構中,都有一個稱為指令指針的寄存器。 這個解決方案的重點是當我們在 function 內部時提取它。

在 amd64 上,以下代碼應為您提供接近 function 的地址。

#include <iostream>

void* foo() {
    void* n;
    asm volatile("lea 0(%%rip), %%rax"
      : "=a" (n));
    return n;
}

auto boo = [](){
    void* n;
    asm volatile("lea 0(%%rip), %%rax"
       : "=a" (n));
    return n;
};

int main() {
    std::cout<<"foo"<<'\n'<<((void*)&foo)<<'\n'<<foo()<<std::endl;  
    std::cout<<"boo"<<'\n'<<((void*)&boo)<<'\n'<<boo()<<std::endl;
}

但例如在 gcc https://godbolt.org/z/dQXmHm上,使用-O3優化級別 function 可能會被內聯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM