Wie erhalte ich die Adresse einer C++-Lambda-Funktion im Lambda selbst?




c++11 c++14 (4)

Dies ist möglich, hängt jedoch stark von der Plattform- und Compileroptimierung ab.

Auf den meisten Architekturen, die ich kenne, gibt es ein Register mit der Bezeichnung Anweisungszeiger. Der Sinn dieser Lösung ist es, sie zu extrahieren, wenn wir uns in der Funktion befinden.

Auf amd64 Der folgende Code sollte Ihnen Adressen geben, die in der Nähe der Funktion eins liegen.

#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;
}

Aber zum Beispiel auf gcc kann https://godbolt.org/z/dQXmHm mit -O3 Optimierungslevel-Funktion eingeblendet sein.

Ich versuche herauszufinden, wie man die Adresse einer Lambda-Funktion in sich selbst findet. Hier ist ein Beispielcode:

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

Ich weiß, dass ich das Lambda in einer Variablen erfassen und die Adresse ausdrucken kann, aber ich möchte es an Ort und Stelle tun, wenn diese anonyme Funktion ausgeführt wird.

Gibt es einen einfacheren Weg?


Eine Möglichkeit, dies zu lösen, besteht darin, das Lambda durch eine handgeschriebene Funktorklasse zu ersetzen. Es ist auch, was das Lambda im Wesentlichen unter der Haube ist.

Dann können Sie die Adresse this , auch ohne den Funktor jemals einer Variablen zuzuweisen:

#include <iostream>

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

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

Ausgabe:

Address of this functor is => 0x7ffd4cd3a4df

Dies hat den Vorteil, dass dies zu 100% portabel und extrem einfach zu überlegen und zu verstehen ist.


Es gibt keine Möglichkeit, die Adresse eines Lambda-Objekts innerhalb eines Lambdas direkt abzurufen.

Nun, wie es passiert, ist dies ziemlich oft nützlich. Die häufigste Verwendung ist, um zu rekursivieren.

Der y_combinator stammt aus Sprachen, in denen Sie nicht über sich selbst sprechen konnten, bis Sie definiert wurden. Es kann ziemlich einfach in c ++ implementiert werden:

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

jetzt kannst du das machen:

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

Eine Variation davon kann beinhalten:

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

wo das self vorbei ist, kann aufgerufen werden, ohne sich self als erstes Argument zu übergeben.

Der zweite entspricht dem echten y-Kombinator (auch als Fixpunkt-Kombinator bekannt), glaube ich. Was Sie wollen, hängt davon ab, was Sie unter 'Adresse von Lambda' verstehen.


Es ist nicht direkt möglich.

Lambda-Erfassungen sind jedoch Klassen und die Adresse eines Objekts stimmt mit der Adresse seines ersten Mitglieds überein. Wenn Sie also ein Objekt nach Wert als erste Erfassung erfassen, entspricht die Adresse der ersten Erfassung der Adresse des Lambda-Objekts:

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

Ausgänge:

0x7ffe8b80d820
0x7ffe8b80d820

Alternativ können Sie ein Dekorationsmuster Lambda erstellen, das den Verweis auf die Lambda-Erfassung an den Aufrufoperator übergibt:

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