2016-07-02 9 views
1

I ein Datenelement haben, das vom Typ ist:Wie anhand Pass mit Lambda funktionieren

std::function<T(T&, T&)>& 

Der Konstruktor übernimmt ein Argument des gleichen Typs.

Wie soll ich eine solche Funktion mit lambdas senden?

Ich habe

versucht
MyClass tmp([](Foo &a, Foo &b) { return a+b; }, ...); 

Aber es funktioniert nicht.

Zum Beispiel:

main.cpp

#include "MyClass.h" 

int main() 
{ 
    MyClass a([](int x, int y) { return x+y;}); 

    return 0; 
} 

MyClass.h

#pragma once 

#include <functional> 

class MyClass 
{ 
    public: 
     MyClass(std::function<int(int, int)>&) noexcept; 
    private: 
     std::function<int(int, int)>& fun; 
}; 
+0

Fehler wie? Mach ein [mcve]. – nwp

+2

Warum müssen Sie eine Nicht-'const'-Referenz * an eine 'std :: -Funktion übergeben? –

+0

@nwp: Fehler in der Art, dass das Übergeben eines prvalue an eine Funktion, die eine Nicht-const-Referenz verwendet, fehlschlägt. –

Antwort

4

Sie einen Lambda auf einen std::function & vorbei. Ein Lambda ist kein std::function also funktioniert das nicht direkt. Ein Lambda ist jedoch in eine std::function umwandelbar, so dass eine temporäre std::function erstellt werden muss, die das Lambda hält.

Da Sie ein std::function & nehmen C++ nimmt an, dass Sie diesen Wert ändern möchten, sonst würde es keinen Sinn machen, es durch nicht-const Referenz zu nehmen. Das Ändern eines Temporären hat keine Auswirkung, daher ist dies nicht sinnvoll, daher erlaubt C++ das nicht.

Eine Möglichkeit, das Problem zu beheben, ist eine const std::function &. Auf diese Weise gibt es keine Änderung eines temporären.

Eine andere Möglichkeit besteht darin, eine tatsächliche std::function zu übergeben, die Sie in main erstellen.

Eine andere Möglichkeit ist es, eine Vorlage zu erstellen, die es Argument an die std::function nur weiterleitet:

class MyClass 
{ 
    public: 
     template <class T> 
     MyClass(T &&t) 
      : fun(std::forward<T>(t)){} 
    private: 
     std::function<int(int, int)> fun; 
}; 

auf diese Weise MyClass etwas nimmt und verwendet es fun zu konstruieren. Beachten Sie, dass fun keine Referenz mehr ist. Die std::function muss irgendwo leben und da es Teil von MyClass ist, macht es Sinn, die Lebensdauer der std::function an MyClass zu binden.

Wenn Sie wirklich wollen, dass fun eine Referenz sein soll, müssen Sie einen Platz dafür finden und sicherstellen, dass es dort bleibt, bis MyClass a; zerstört wird. Ich empfehle diesen Weg nicht, da es immer schwieriger wird, sicherzustellen, dass die Lebensdauern korrekt sind.

Sie können das Lambda auch direkt speichern, aber das ist ein bisschen schwierig und abhängig davon, was Sie eigentlich mit MyClass tun möchten, kann es nicht lebensfähig sein.

+0

"Eine andere Möglichkeit besteht darin, eine Vorlage zu erstellen, die nur ihr Argument weiterleitet" - Es gibt keinen Vorteil, wenn man nur eine 'std :: function' nach Wert nimmt und move-construction 'fun' daraus macht. Oder sogar dein früherer Vorschlag, es mit "const &" zu nehmen und davon zu kopieren. Was Sie getan haben, bedeutet, dass Typeigenschaften nicht mehr erkennen können, dass 'MyClass' nicht von' int' konstruierbar ist, da die Instanziierung des Konstruktors viel zu spät für SFINAE fehlschlagen würde. – hvd

+0

@nwp Ich habe eine temporäre Funktion wie diese versucht : 'auto fun = [] (int x, int y) -> int & {return x + y;};' Aber es funktioniert nicht. –

+0

@ user6180573 Ich meinte so etwas wie 'std :: function f = [] (int x, int y) {return x + y;};' und dann 'MyClass a (f);' . – nwp