Richtiger Weg, um ein Lambda als Parameter per Referenz zu erhalten

Lesezeit: 4 Minuten

Benutzer-Avatar
lurscher

Was ist der richtige Weg, um eine Funktion zu definieren, die a erhält? int->int Lambda-Parameter nach Referenz?

void f(std::function< int(int) >& lambda);

oder

void f(auto& lambda);

Ich bin mir nicht sicher, ob die letzte Form überhaupt eine legale Syntax ist.

Gibt es andere Möglichkeiten, einen Lambda-Parameter zu definieren?

  • Warum brauchen Sie das Lambda als Referenz? Meinst du const&?

    – geschickt_code

    23. Juni 2011 um 18:13 Uhr


Benutzer-Avatar
bdonlan

Sie können keine haben auto Parameter. Sie haben grundsätzlich zwei Möglichkeiten:

Option 1: Verwenden std::function wie du gezeigt hast.

Option 2: Verwenden Sie einen Vorlagenparameter:

template<typename F>
void f(F &lambda) { /* ... */}

Option 2 kann in einigen Fällen effizienter sein, da sie eine potenzielle Heap-Zuweisung für das eingebettete Lambda-Funktionsobjekt vermeiden kann, aber nur dann möglich ist f kann als Template-Funktion in einem Header platziert werden. Es kann auch die Kompilierungszeiten und den I-Cache-Fußabdruck erhöhen, wie dies bei jedem Template der Fall sein kann. Beachten Sie, dass dies möglicherweise auch keine Auswirkungen hat, da das Lambda-Funktionsobjekt, wenn es klein genug ist, inline in dargestellt werden kann std::function Objekt.

  • Vorlagen können auch den I-Cache-Fußabdruck verbessern, indem Sprünge zu allgemeinem nicht lokalem Code eliminiert werden (in diesem Fall führen Sie Ihr Lambda direkt aus, ohne durch den allgemeinen Zweck springen zu müssen std::function Verpackung zuerst)

    – jalf

    23. Juni 2011 um 18:17 Uhr

  • Dieses Zitat, “Wenn das Lambda-Funktionsobjekt klein genug ist, kann es inline in der dargestellt werden std::function Objekt” ist irreführend. Lambdas sind immer für Inline verfügbar (der Compiler kann sich natürlich dagegen entscheiden). std::function Implementierungen verwenden im Allgemeinen die Optimierung kleiner Objekte, um Heap-Zuweisungen zu vermeiden. Wenn ein Lambda klein genug ist Capture-Liste es wird darin gespeichert std::function ohne den Haufen zu benutzen. Abgesehen davon hat die Größe eines Lambdas keine wirkliche Bedeutung.

    – geschickt_code

    23. Juni 2011 um 18:20 Uhr


  • @bdonlan: Übrigens, warum ist da & in void f(F & lambda)?

    – Nawaz

    23. Juni 2011 um 18:20 Uhr

  • @bdonlan: Aber die Konstante & geht davon aus, dass die Mitglieder des Lambda (die Capture-by-Values) nicht geändert werden können. Was möglicherweise nicht das ist, was der Benutzer möchte.

    – Nicol Bolas

    24. Juni 2011 um 1:57 Uhr

  • @bdonlan Es ist eine Weile her, aber das Übergeben als nicht konstante Referenz erlaubt keine Konstruktion eines temporären Lambda im Funktionsaufruf. Hier wäre eine R-Wert-Referenz am besten.

    – zennehoy

    11. September 2013 um 8:42 Uhr

Benutzer-Avatar
Nawaz

ich würde … benutzen template wie:

template<typename Functor>
void f(Functor functor)
{
   cout << functor(10) << endl;
}

int g(int x)
{
    return x * x;
}
int main() 
{
    auto lambda = [] (int x) { cout << x * 50 << endl; return x * 100; };
    f(lambda); //pass lambda
    f(g);      //pass function 
}

Ausgabe:

500
1000
100

Demo: http://www.ideone.com/EayVq

Ich weiß, es ist 7 Jahre her, aber hier ist ein Weg, den sonst niemand erwähnt hat:

void foo(void (*f)(int)){
    std::cout<<"foo"<<std::endl;
    f(1); // calls lambda which takes an int and returns void
}
int main(){
    foo([](int a){std::cout<<"lambda "<<a<<std::endl;});
}

Welche Ausgänge:

foo
lambda 1

Keine Notwendigkeit für Vorlagen oder std::function

  • Dies ist nur auf Lambdas beschränkt, die in Funktionszeiger zerfallen können (Lambdas ohne Captures), und erfordert auch die Angabe einer genauen Signatur (wie bei for std::function Fall), während die Vorlagenversion diese Einschränkung nicht hat.

    – Andriy Tylychko

    27. April 2019 um 23:46 Uhr

  • Vielen Dank dafür!

    – Mike Lee

    8. Januar 2021 um 18:24 Uhr

Seit C++ 20,

void f(auto& lambda);

funktioniert tatsächlich (es ist eine abgekürzte Funktionsvorlage):

Wenn Platzhaltertypen (entweder auto oder Concept auto) in der Parameterliste einer Funktionsdeklaration oder einer Funktionsvorlagendeklaration erscheinen, die Deklaration eine Funktionsvorlage deklariert und ein erfundener Vorlagenparameter für jeden Platzhalter an die Vorlagenparameterliste angehängt wird

und es entspricht genau Option 2 in @bdonlans Antwort:

template<typename F>
void f(F &lambda) { /* ... */}

void f(auto& lambda);

Das ist knapp. Was tatsächlich kompiliert wird, ist:

#include <cassert>

/*constexpr optional*/ const auto f = [](auto &&lambda)
{
  lambda();
  lambda();
};

int main()
{
  int counter = 0;
  f([&]{ ++counter; });
  assert(counter == 2);
}

1015850cookie-checkRichtiger Weg, um ein Lambda als Parameter per Referenz zu erhalten

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy