Frage zu lvalue / rvalue Referenzen



  • Ich habe oft Funktionen, bei denen man die Argumente nicht kopieren muss, egal ob sie lvalues oder rvalues sind.
    Aber man muss sich ja bei Referenzen immer für eins entscheiden, & oder &&.
    Kann man irgendwie machen, dass es dem Compiler egal ist, ob das Argument ein lvalue oder ein rvalue ist?
    Einfach &&& funktioniert nicht, habe ich schon ausprobiert.

    Edit:
    Es soll also was ähnliches wie das hier kompilieren:

    void foo(int& x) {}
    int main() {
        int x{3};
        foo(x);
        foo(3);
    }
    


  • Timon Paßlick schrieb:

    Kann man irgendwie machen, dass es dem Compiler egal ist, ob das Argument ein lvalue oder ein rvalue ist?

    Reicht dir const T& ?



  • Dann würde die Funktion ja nur konstante lvalues vom Typ T annehmen, oder?



  • Es gibt Universal Reference Parameter Types (werden in Effective Modern C++ erklaert).

    template <typename T>
    void foo(T &&arg)
    {
    
    }
    

    *Edit
    Universal References in C++ - Scott Mayers.



  • Timon Paßlick schrieb:

    Dann würde die Funktion ja nur konstante lvalues vom Typ T annehmen, oder?

    Nö.
    const T& sollte mit allem gehen.
    Die Frage ist nur ob der Funktion eine "reference to const" reicht.



  • Also nimmt const T& alles an, aber T& nicht. Dankeschön, aber ich sehe mir wahrscheinlich lieber den Link an. Trotzdem, gut zu wissen. ( :



  • Übrigens, ich frag nicht für ne bestimmte Funktion, sondern generell.



  • Diese universal references sind total instabil. Anstatt einer Schnittstelle für einen garbage collector könnte man doch einen universal reference Operator einbauen.
    Was ist eigentlich, wenn ich nur rvalues von Typ T möchte? Geht dann ja nicht.



  • Timon Paßlick schrieb:

    Was ist eigentlich, wenn ich nur rvalues von Typ T möchte? Geht dann ja nicht.

    Schau dir mal std::enable_if und std::is_rvalue_reference an. Geht schon.



  • Timon Paßlick schrieb:

    Diese universal references sind total instabil. Anstatt einer Schnittstelle für einen garbage collector könnte man doch einen universal reference Operator einbauen.

    Du hast mich hiermit völlig verloren. Was meinst du mit "instabil"? Was hat das mit einem GC zu tun?

    Der Standard-Term ist inzwischen übrigens "forwarding reference", siehe auch N4164

    Was ist eigentlich, wenn ich nur rvalues von Typ T möchte? Geht dann ja nicht.

    Beachte, dass das NUR in templates gilt und bei auto&& . Wenn T ein konkreter Typ ist (und nicht das Template T), dann handelt es sich nicht um eine forwarding reference.

    Edit: ich habe dein eigentliches Problem noch immer nicht verstanden. Was stimmt nicht mit Hustbaers Vorschlag, einfach const T& zu nehmen? Wenn du non-const haben willst, was soll dann foo(3) bedeuten? Das ergibt doch keinen Sinn.



  • foo() war doch nur ein Beispiel. Ich ärger mich bei jeder Funktion, die ich schreibe, ein bisschen, dass ich mich zwischen lvalue und rvalue entscheiden muss. Dass das nur für Templates und auto gilt, habe ich schon verstanden. Deshalb habe ich mich auch gestern aufgeregt, warum nicht für alles verfügbar machen?



  • Timon Paßlick schrieb:

    foo() war doch nur ein Beispiel.

    Ich verstehe nur nicht, was du mit einer rvalue-Referenz bei dem Beispiel erreichen willst. Also ein Beispiel, an dem mir dein Problem nicht klar wird.

    Timon Paßlick schrieb:

    Ich ärger mich bei jeder Funktion, die ich schreibe, ein bisschen, dass ich mich zwischen lvalue und rvalue entscheiden muss.

    Aber es ist doch eigentlich immer ziemlich klar, welches von beiden man verwenden muss?

    Mach doch mal ein sinnvolles Beispiel, das das Problem zeigt. Ich wage mal zu behaupten, dass in normalem nicht-library-Code rvalue-Referenzen nur selten vorkommen.



  • Ok, zum Beispiel hier:

    //Laut "Accelerated C++" von A. Koenig und B. Moo besser als %
    int nrand(int &&n) {
        int bucketSize = RAND_MAX / n;
        return rand() / bucketSize;
    }
    

    Warum sollte sich die Funktion auf rvalues beschränken? Oder auf lvalues? Sie kann doch locker mit beidem arbeiten.



  • Das ist kein sinnvolles Beispiel. Du änderst n hier nicht. Es gibt hier überhaupt keine Veranlassung für int&& / int& . Einfach nrand(int n) . Und auch mit nrand(const int &n) hättest du keine Probleme.



  • Stimmt. Schließen wir den Thread hier einfach, ich weiß jetzt, was ich wissen muss.



  • Timon Paßlick schrieb:

    Ok, zum Beispiel hier:

    //Laut "Accelerated C++" von A. Koenig und B. Moo besser als %
    int nrand(int &&n) {
        int bucketSize = RAND_MAX / n;
        return rand() / bucketSize;
    }
    

    Warum sollte sich die Funktion auf rvalues beschränken? Oder auf lvalues? Sie kann doch locker mit beidem arbeiten.

    Dann nimm einfach int const& .
    ( std::string const& wäre ein besseres Beispiel, da einen int zu kopieren billigst ist - d.h. wenn da wirklich konkret int steht würde man einfach int als Parameter nehmen.)



  • Ich weiß, hat ja schon wob erwähnt. Habs verstanden, wieso es ausreicht, wie es gerade ist.
    Wenn das Argument nicht verändert wird, dann ist es egal, ob links oder rechts. Wenn es verändert werden soll, dann sollte es eine Adresse im Aufruferscope haben, sonst bekommt man das veränderte Objekt nicht zurück. Und für Spezialsachen braucht man rvalue-Referenzen.


Anmelden zum Antworten