2015-10-03 15 views
11

Mam klasę, która ma wskaźnik funkcji do funkcji jądra, która może zmieniać się z zewnątrz.C++ lambda - zmienna składowa przechwytywania

class Bar 
{ 
    public: 
    int i; 
} 

class Foo 
{ 
    public: 
    std::function<double()> kernel; 
    Bar bar;   
}; 

int main() 
{ 

    Foo f; 
    f.kernel = []() -> double { return i * i; }; //this is not working obviously 

} 

Jak uzyskać zachowanie "prezentowane", np. odczytaj zmienne klasy wewnątrz lambda. Mogę ominąć to przechodząc f w środku i napisać f.bar.i, ale to nie jest dobre rozwiązanie.

+1

Co jest nie tak z '[& f]() {return f.i * f.i; } '? –

+0

@KerrekSB Poddałem edycji pytanie –

+0

Więc zasadniczo chcesz wywołać 'f.kernel()' i 'kernel' powinien automatycznie być związany z' f' tak, jakby był funkcją członka? – dhke

Odpowiedz

17

w C++ 14 można napisać go jak

f.kernel = [&i = f.bar.i]() -> double { return i * i; }; 

Jeśli nie masz C++ 14, można alternatywnie tworzyć innej zmiennej,

int &i = f.bar.i; 
f.kernel = [&i]() -> double { return i*i; }; 

Choć nie ma nic źle z przekazaniem f i pisaniem f.bar.i.

+0

. Ale to wiąże lambda z jądrem do tego konkretnego przykładu 'f', czyż nie? Dlatego jeśli zrobię 'f2.kernel = f.kernel' i wywołaję' f2.kernel() 'otrzymam' i' z 'f'? To nie może być problem. – dhke

+1

tylko FYI kompilując pierwszy przykład z g ++ -std = C++ 11 daje 'ostrzeżenie: inicjatory wychwytywania lambda dostępne tylko z -std = C++ 14 lub -std = gnu ++ 14' więc jest to funkcja C++ 14 – NathanOliver

+0

@NathanOliver Usunięto "uwierz". @dhke Tak, jeśli skopiujesz 'kernel' z' f' na 'f2', to będziesz używał tej samej funkcji, jeśli wywołasz ją z obu instancji. – aslg

7

Wygląda na to, że you cannot do so. Nie ma konstrukcji umożliwiającej utworzenie funkcji lambda.

Ale pewnie można śledzić @ sugestią KerrekSB i oprócz tego wysłania wezwanie do jeszcze dostać funkcji użytkownika:

class Foo 
{ 
public: 
    double kernel() 
    { 
     _kernel(*this); 
    } 

    std::function<double(Foo &)> _kernel; 
}; 


Foo f; 
f._kernel = [](Foo &f) -> double { return f.i * f.i; }; 
f.kernel() 

pamiętać, że nie można nazwać oba pola kernel.

+0

Podoba mi się również to rozwiązanie. Można również utworzyć statyczne słowo "_kernel", aby wszystkie wystąpienia miały tę samą "funkcję składową". – aslg

0

Funkcja lambda nie ma informacji o i lub Bar. Jak to możliwe? Musisz podać referencję. Jeśli definiujesz ciało funkcji inaczej, możesz przekazać i jako parametr i wywołasz go w klasie, a otrzymasz to, czego chcesz.

Powiązane problemy