std::function generisch speichern



  • Hi,

    ich würde gerne std::function verschiedenen Typs einheitlich speichern, zB. in einer std::map.

    Zwei Ansätze habe ich, doch beim Zweiten weiß ich nicht, ob das legales C++ ist (oder vielleicht UB *fürcht*):

    // 1. Ansatz
    
    std::function<void()> ff;
    Derived* d;
    
    void Save(const std::function<void(Derived*)>& f)
    {
    	ff = [f]{ f(d); };
    }
    
    void Call()
    {
    	d = new Derived;
    	ff();
    }
    
    // 2. Ansatz
    
    std::function<void(Base*)> ff;
    
    void Save(const std::function<void(Derived*)>& f)
    {
    	ff = reinterpret_cast<const std::function<void(Base*)>&>(f); // ist das OK?
    }
    
    void Call()
    {
    	ff(new Derived);
    }
    
    // Benutzung
    
    Save([](Derived* d)
    {
    	cout << "DER: "  << d->b << endl;
    });
    
    Call();
    

    Was meint ihr?
    Der Code dient natürlich nur zur Veranschaulichung.
    Danke!



  • Was ist überhaupt dein Ziel? Eine std::function mit einem Parameter zu einer mit keinen Parametern, von std::function<void(Base*)> zu std::function<void(Derived*)> oder von Derived zu Base? Wenn du die Anzahl der Parameter ändern willst ist verpacken in eine Lambda Funktion schon das richtige. Nur mit der globalen Variable ist unschön. Der reinterpret_cast ist böse und sorgt mit großer Sicherheit für einen Absturz in deinem Programm. Die Konvertierung von Base zu Derived scheint übrigens automatisch zu funktionieren. Anders herum brauchst du wieder eine Lambda Funktion.



  • Ich möchte Lambdas mit verschiedenen Derived-Typ-Parametern für einen späteren Aufruf in einer std::map speichern.

    Dabei soll der Funktion ein Lambda mit Derived* Parameter übergeben werden, damit ich nicht immer...

    Save([](Base* b)
    {
        Derived* d = static_cast<Derived*>(b); // ...dies...
        cout << "DER: "  << d->b << endl;
    });
    

    ...schreiben muss.

    Die Funktion ist eigentlich ein Template, und die globale Variable dient, wiegesagt, nur zur Veranschaulichung.

    Warum Absturz? Ich stelle schon sicher, dass immer ein Objekt mit korrektem Typ übergeben wird.



  • Dann pack die Konvertierung zu Derived doch in der Save Funktion dazu:

    void Save(const std::function<void(Derived*)>& f)
    {
      ff = [f](Base* b) { f(static_cast<Derived*>(b)); };
    }
    

    Miau schrieb:

    Warum Absturz? Ich stelle schon sicher, dass immer ein Objekt mit korrektem Typ übergeben wird.

    Du Konvertierst aber einfach Referenzen auf std::function zu einem std::function mit anderen Template Parametern. Dank reinterpret_cast frisst der Compiler alles. Du könntest damit auch ein int zu einer Referenz auf eine std::function casten. Ich habe deine Variante 2 gerade mal getestet und es gab sogar das erwartete Verhalten. Allerdings ist das keinesfalls garantiert und spätestens mit Mehrfachvererbung oder Polymorphie, wo es zwischen Pointer auf Base und Derived einen Offset geben kann, wird es sowieso nicht mehr wie gewünscht funktionieren.



  • Ja, ich wollte bloß wissen, ob der std::function-cast OK ist...
    Aber war wohl ne blöde Idee 😉

    Habe es jetzt mit dem zwischen-lambda (1. Ansatz) gelöst, musste nun außerdem doch unterschiedliche Parameteranzahlen unterstützen.

    Das neue C++ ist schon geil 😋


Log in to reply