std::bind nicht kompatibel mit movable-only types?



  • Eigentlich selbsterklärend...

    #include <functional>
    
    struct movable_only
    {
            movable_only() = default;
    
            movable_only(movable_only const&) = delete;
            movable_only& operator = (movable_only const&) = delete;
    
            movable_only(movable_only&&) {}
            movable_only& operator = (movable_only&&) {}
    };
    
    void f(movable_only m)
    {}
    
    int main()
    {
            movable_only a;
            auto fun = std::bind(f, std::move(a));
            fun();
    }
    

    http://ideone.com/1anmF
    Warum klappts nicht? Was kann ich tun?

    Grüßle,
    PI



  • funktioniert das hier?

    int main()
    {
            movable_only a;
            f(a);
    }
    


  • Wenn du darauf hinaus willst, dass ich als Parameter eine Referenz verwenden soll: Nein, das kompiliert ebenfalls nicht.



  • Der originale Code kann gar nicht funktionieren. __cu hat durch sein Beispiel darauf hingewiesen, denn std::bind benutzt kein std::forward oder std::move, um die Parameter weiterzuleiten.

    Davon abgesehen, hätte ich erwartet, dass es mit einer Funktion wie dieser:

    void f(movable_only const& m)
    {}
    

    hätte funktionieren müssen (vielleicht sogar ohne const, bin mir da aber gerade nicht sicher). Welchen Compiler in welcher Version hast Du verwendet?

    Cheers!
    k.k.



  • GCC 4.6.1 😉
    Funktioniert weder mit ref, noch mit const-ref. 😞



  • Mit dem g++ 4.7.0 (20111112) funktioniert es mit der Referenz. (auch ohne const).



  • Soll a hier einmal in den Binder gemoved und bei jedem Aufruf von fun dann kopiert werden?



  • int main()
    {
            movable_only a;
            auto fun = std::bind(f, std::move(a)); // der move in den binder funktioniert
            fun();                                 // aber wenn hier "gemovt" wird     
            fun();                                 // ?
    }
    


  • Eigentlich bräuchte man so etwas:

    std::move(fun)();
    

    Das bedingt allerdings folgende Spracherweiterung:

    class foo {
      void bar();       // normal
      void bar() const; // constant
      void bar() &&;    // destructive
    };
    

    Auf den ersten Blick (und genauer habe ich das nicht bedacht) ist das gar nicht so sinnlos.



  • destructivus schrieb:

    Eigentlich bräuchte man so etwas:

    std::move(fun)();
    

    Das gefällt mir!

    destructivus schrieb:

    Das bedingt allerdings folgende Spracherweiterung:

    class foo {
      void bar();       // normal
      void bar() const; // constant
      void bar() &&;    // destructive
    };
    

    Auf den ersten Blick (und genauer habe ich das nicht bedacht) ist das gar nicht so sinnlos.

    Naja, das ist nicht ganz richtig so mit der Überladung (sie ist illegal). Entweder ist ein Ref-Qualifier überall dabei oder eben nirgens. Korrekt wäre:

    class some_binder {
      :::
      result_type operator()(...) &;
      result_type operator()(...) const&;
      result_type operator()(...) &&;
      :::
    };
    

    Die Semantik im Falle von Ref-Qualifiers ist dieselbe, die man bei "normalen" Parametern des entsprechenden Typs auch hat bzgl Überladung:

    void foo(bar      & self);
    void foo(bar const& self);
    void foo(bar     && self);
    

    clang unterstützt das mit den ref-qualifiers inzwischen angeblich.

    Ja, so könnte man im letzten Overload die gebundenen Parameter beim Aufruf der "inneren Funktion" auch zu Rvalues casten.



  • destructivus schrieb:

    Das bedingt allerdings folgende Spracherweiterung:

    class foo {
      void bar();       // normal
      void bar() const; // constant
      void bar() &&;    // destructive
    };
    

    Auf den ersten Blick (und genauer habe ich das nicht bedacht) ist das gar nicht so sinnlos.

    Auch auf den zweiten nicht. Aus dem Grund gibts das Feature auch in C++0x. Meines Wissens wirds aber von MSVC und gcc noch nicht unterstützt...


Anmelden zum Antworten