2

Ich habe den folgenden Code, der versucht, Prozeduren in CPS-Form zu definieren.Segmentierungsfehler beim Aufruf von Lambda-Returns von der Funktion höherer Ordnung in C++ 11

#include <iostream> 
#include <utility> 
#include <type_traits> 
#include <string> 

using namespace std; 


template <typename T> using Func = std::function<T>; 
template <typename T> using Cont = Func<void (T &&)>; 
template <typename T, typename U> using Proc = Func<void (T &&, Cont<U>)>; 

template <typename T> struct RevProc; 
template <typename T, typename U> struct RevProc<Proc<T, U>> { 
    using ArgType = T; 
    using RetType = U; 
}; 

template <typename P1, typename P2> auto pipe(P1 proc1, P2 proc2) 
    -> Proc<typename RevProc<P1>::ArgType, typename RevProc<P2>::RetType> { 
    using T = typename RevProc<P1>::ArgType; 
    using U = typename RevProc<P2>::ArgType; 
    static_assert(is_same<U, typename RevProc<P1>::RetType>::value, 
    "Mismatch procedure type."); 
    using V = typename RevProc<P2>::RetType; 
    return [&] (T &&t, Cont<V> pass) { 
    proc1(move(t), [&] (U &&u) { 
     proc2(move(u), pass); 
    }); 
    }; 
} 
template <typename P1, typename P2, typename... Ps> auto pipe(P1 proc1, P2 proc2, Ps ...procs) 
    -> Proc<typename RevProc<P1>::ArgType, typename RevProc<decltype(pipe(proc2, procs...))>::RetType> { 
    auto proc2s = pipe(proc2, procs...); 
    return pipe(proc1, proc2s); 
} 

int main() { 
    Func<void()> var1; 
    Cont<int> var2([] (int &&x) {}); 
    Proc<int, int> var3([] (int &&x, Cont<int> pass) { 
    pass(x + 1); 
    }); 
    auto var4 = pipe(var3, var3); 
    var4(42, [] (int &&x) { 
    cout << x << endl; 
    }); 
    Proc<string, int> var5([] (string &&str, Cont<int> pass) { 
    pass(str.length()); 
    }); 
    // auto var6 = pipe(var5, var5); 
    Proc<int, int> var7 = pipe(var3, var3, var3); 
    // var7(42, [] (int &&x) { 
    // cout << x << endl; 
    // }); 
    auto var8 = pipe(var5, var3, var3); 
    var8("something", [] (int &&x) { 
    cout << x << endl; 
    }); 

    return 0; 
} 

Wenn ich var6 Zeile Kommentar-, der Compiler einen Fehler aus, wie erwartet. Wenn jedoch entweder der Aufruf von var7 oder var8 unkommentiert ist, besteht der Code die Kompilierung, aber zur Laufzeit wird ein zufälliger Segmentierungsfehler oder Busfehler ausgelöst. Der Code ist während des Aufbaus des Lambda sicher, stürzt aber beim Anwenden ab.

Danke für das Hinweis auf meine fehlerhafte.


Es kann sinnvoll sein, zu ergänzen, dass es gut läuft, wenn ich den Code zu

var7 = pipe(var3, pipe(var3, var3)); 

So wie var8 ändern.


Ich versuchte zufällig, und es zu meiner Überraschung behoben. Ich behalte nur die erste Deklaration und modifiziere die zweite, indem ich die erste kopiere:

Also, was zur Hölle?

+0

Was ist der Grund dafür, 'auto proc2s' zu deklarieren, aber nicht zu benutzen? –

+0

Sorry, das war nur Debug-Personal. Bearbeitet. – Cowsay

Antwort

2

Ihre Pipe-Implementierung hat ein undefiniertes Verhalten. Es erfasst alles per Referenz, also auch die Funktionsparameter der Pipes, die nach dem Ende der Pipe-Funktion zerstört werden. Entweder durch Kopieren [=] erfassen oder als Referenz an Pipe übergeben.

+0

Ehrfürchtig. Es stellt sich heraus, dass nur "proc1" als Referenz erfasst werden kann, da die Konstruktion des Lambda, das "proc2" und "pass" nennt, verzögert ist. Es ist schwer, meine Gedanken aus Sprachen mit GC zu transformieren. Vielen Dank. – Cowsay

+0

Übrigens habe ich nach hartem Versuch herausgefunden, wie man eine CPS-Version von 'pipe' schreibt, die in der Lage ist, alles als Referenzen in allen Ebenen von Lambda zu erfassen. Ziemlich spaßig! – Cowsay

Verwandte Themen