2015-07-22 9 views
5

Mam następującą funkcjęJak przekazać wartość rvalue C++ functor do przechwytywania lambda?

template<class Function> 
void f(Function&& g) { 
    h(..., [&g](){g();}); 
} 

Jest to funkcja f przyjmując funkcję lambda lub funktor jako argument. Wewnątrz wywołuje funkcję h, do której przekazuję lambdę jako argument, który wywołuje g i odbiera g przez przechwycenie.

  1. Czy powinienem podać g lub &g w polu przechwytywania lambda?
  2. Czy funktor będzie skopiowany z powyższym kodem?
+1

normalnie pełnić podobną obiekty są przekazywane przez wartość. Kopiowanie ich powinno być niezwykle tanie. Jeśli twoje obiekty nie są takie, prawdopodobnie robisz coś nie całkiem w porządku. –

Odpowiedz

2

Jeśli uchwycić g przez odniesienie, to znaczy, ze składnią &g przedstawionego we fragmencie, nie kopia zostanie wykonana. To jest preferowany sposób. Powinieneś kopiować tylko wtedy, gdy lambda może zostać wywołana po zakończeniu f, co potencjalnie oznacza zniszczenie obiektu, o którym mowa g.
W takim przypadku, spedycja mogłyby być tańsze choć:

template<class Function> 
void f(Function&& g) { 
    h(…, [g=std::forward<Function>(g)] {g();}); 
} 
+2

Należy zauważyć, że tutaj wykonujesz kopię/ruch oryginalnego 'g'. zobacz [perfekcyjne przechwytywanie-perfekcyjne-forwarder-uniwersalny-referencyjny-w-a-lambda] (http://stackoverflow.com/questions/31410209/perfectly-capturing-a-perfect-forwarder-universal-reference-in -a-lambda/31410880 # 31410880) – Jarod42

+2

@ Jarod42 To była moja intencja. – Columbo

+1

Zobacz odpowiedź @ Dietera, jeśli potrzebujesz równoważnego rozwiązania, które działa z C++ 11 – chmike

1

Konstruujesz lambdę, która nie przyjmuje żadnych argumentów i niczego nie zwraca. Ale już masz takiego funktora: g! Należy tylko naprzód go:

template<class Function> 
void f(Function&& g) { 
    h(..., std::forward<Function>(g)); 
} 
+2

Podejrzewam, że OP właśnie to skróciło, aw rzeczywistości lambda robi więcej. – Ishamael

+4

@Ishamael Następnie OP powinien umieścić to, co OP chce zrobić w pytaniu, tak, że nie muszę zgadywać. – Barry

+1

Jak powiedział @Ishamael, usunąłem kod do jego najprostszej postaci. Lambda robi znacznie więcej, niż wywołuje argumenty 'g()' i 'g()' i zwraca wynik. Masz rację: @Barry, powinienem był to jasno sformułować, aby lambda nie była zoptymalizowana w odpowiedziach. – chmike

1

Można to zrobić:

template<class Function> 
void f(Function&& g) { 
    Function f(std::move(g)); 
    int additional = 0; 
    h(..., [&f, additional](){f(additional);}); 
} 
+1

Ta odpowiedź ma zaletę, aby pracować z C++ 11. Odpowiedź @Columbo wymaga C++ 14. Wybrałem jego odpowiedź jako poprawną odpowiedź, ponieważ jest to nowy standardowy sposób, aby to zrobić. Ale użyję twojej odpowiedzi, dopóki nie przejdę na C++ 14. Twój wkład był pomocny. – chmike

+0

AFAICS, w ten sposób nie ma żadnej korzyści w porównaniu do oryginalnego podejścia @chmikes. Przede wszystkim "poruszasz się", gdy powinieneś "forwardować". Po drugie, 'f' jest przechwytywane przez odniesienie, a jego czas życia nie przekracza wartości' g', więc faktycznie 'f' jest zbędne. – Columbo

+0

@columbo Najwyraźniej mój kompilator (4.9.2) wymaga, aby 'f' było przekazywane przez odniesienie. Ten kod działa. Nie jestem pewna różnicy, która spowodowałaby użycie "forward". – chmike

Powiązane problemy