ラムダ自体内でC++ラムダ関数のアドレスを取得する方法は?




c++11 lambda (4)

私はラムダ関数のアドレスをそれ自身の中で取得する方法を見つけようとしています。 サンプルコードを次に示します。

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

変数でラムダをキャプチャしてアドレスを出力できることは知っていますが、この匿名関数が実行されているときに適切に実行したいと思います。

もっと簡単な方法はありますか?


これを解決する1つの方法は、ラムダを手書きのファンクタークラスに置き換えることです。 ラムダが基本的に内部にあるものでもあります。

次に、ファンクタを変数に割り当てなくても、これを介してアドレスを取得できます。

#include <iostream>

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

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

出力:

Address of this functor is => 0x7ffd4cd3a4df

これには、100%ポータブルであり、推論と理解が非常に簡単であるという利点があります。


ラムダをキャプチャします。

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

可能ですが、プラットフォームとコンパイラの最適化に大きく依存します。

私が知っているほとんどのアーキテクチャには、命令ポインタと呼ばれるレジスタがあります。 このソリューションのポイントは、関数内にいるときに抽出することです。

amd64では、次のコードで関数1に近いアドレスが提供されます。

#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 最適化レベル関数がインライン化されている場合があります。


直接は不可能です。

ただし、ラムダキャプチャはクラスであり、オブジェクトのアドレスはその最初のメンバーのアドレスと一致します。 したがって、値によって1つのオブジェクトを最初のキャプチャとしてキャプチャする場合、最初のキャプチャのアドレスはラムダオブジェクトのアドレスに対応します。

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

出力:

0x7ffe8b80d820
0x7ffe8b80d820

または、ラムダキャプチャへの参照を呼び出し演算子に渡す デコレータデザインパターン 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();
}




c++17