[英]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
來自在定義之前您無法談論自己的語言。 它可以很容易地在c++中實現:
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。
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.