2017-02-09 19 views
5

Staram się realizować ten kawałek funkcji wyższego rzędu w python przy użyciu C++:Różne wyniki uzyskane za pomocą rodzajowe lambdy oraz funkcję automatycznego typu zwrot w C++ 14

def add1(x): 
    def helper(): 
     nonlocal x 
     x += 1 
     return x 
    return helper 

Oto trzy wersje I utworzona:

#include <iostream> 
#include <functional> 

using namespace std; 

function<int(void)> add1_v1(int x) { 
    function<int(void)> g = [&x]() {return ++x;}; 
    return g; 
} 

auto add1_v2(int x) { 
    function<int(void)> g = [&x]() {return ++x;}; 
    return g; 
} 

auto add1_v3(int x) { 
    auto g = [&x]() {return ++x;}; 
    return g; 
} 

int main() { 
    auto a = add1_v1(100); 
    auto b = add1_v2(100); 
    auto c = add1_v3(100); 
    for(int i = 0; i < 3; ++i) { 
     cout << a() << endl; 
    } 
    cout << "-------------------------------------------" << endl; 
    for(int i = 0; i < 3; ++i) { 
     cout << b() << endl; 
    } 
    cout << "-------------------------------------------" << endl; 
    for(int i = 0; i < 3; ++i) { 
     cout << c() << endl; 
    } 
    return 0; 
} 

wyjścia są:

101 
102 
103 
------------------------------------------- 
4239465 
4239466 
4239467 
------------------------------------------- 
4201325 
4201325 
4201325 

Tylko add1_v1 pasuje to, co chcę. Czy ktoś może wyjaśnić mi przyczynę?

+0

Co to znaczy „nie działa” oznacza? – Brian

+0

@Brian Zrewidowano problem. –

+0

Oni wszyscy są w błędzie. 'add1_v1' ma szczęście. – immibis

Odpowiedz

7

Powodem jest niezdefiniowane zachowanie.

Wewnętrzna lambda przechwytuje x przez odniesienie.

Problem polega na tym, że jak tylko add() powraca, jego parametr ulega zniszczeniu, a zwrócona wartość lambda ma zwisające odniesienie do zniszczonego obiektu.

Lambda musi przechwycić wartość x; i jak to wygląda dla mnie jesteś naprawdę staramy się robić o to mutable lambda:

auto add(int x) { 
    function<int(void)> g = [x]() mutable {return ++x;}; 
    return g; 
} 

Należy zauważyć, że takie podejście niesie pewne konsekwencje, jeśli chodzi o kopiowanie następnie zwrócony lambda; ale dopóki zwrócony lambda pozostaje "w jednym miejscu", przez cały pozostały czas życia, wynikowa semantyka będzie prawdopodobnie tym, czego oczekujesz.

+1

'auto long_live_x = make_shared (x); return [=]() {return ++ * long_live_x;}; 'jest również możliwy, z różnymi kompromisami. – ephemient

4

Wszystkie z nich są źle sformułowane, ponieważ jesteś przechwytywanie x przez odniesienie lambda, ale x jest zmienna lokalna i zostanie zniszczona, kiedy wyjść z funkcji add, a następnie odniesienie staje Dynda, dereference na nim ostatnie powoduje UB, co oznacza, że ​​wszystko jest możliwe; nawet pierwszy przypadek wydaje się działać dobrze.

0

nie odpowiedź, wszystko wydaje się wersja funkcji działa dobrze, jeśli zmienić podpis parametru do add1_v * (int & & X)