Template Parameterübergabe



  • Hallo zusammen
    Ich muss gestehen, ich habe einige Schwierigkeiten in Bezug auf die Implementierung von Template Funktionen. Nehmen wir bspw. mal das folgende Konstrukt:

    template<typename T> class DataStructure{
     T &Add(T &t){
      // <<save T into the underlying Datastructure>> 
      return t;
     }
    
    };
    

    Nun habe ich folgende Probleme beim Aufruf:

    int a = 5;
    DataStructure ds;
    ds.Add<int*>(&a); // cannot convert parameter 1 from 'int *' to 'int *&'
    

    Wie rufe ich denn das korrekt auf, resp. wie sieht die korrekte Funktionsdeklaration aus?

    Natürlich könnte ich einfach alles by Value übergeben, dann würde alles perfekt harmonieren, weil er dann beim Zeigertypen auch einfach einen Zeiger erwartet und bei NICHT Zeigern ist es ihm dann egal ob der Wert aus einer Variable kommt oder nicht. Allerdings hätte ich in diesem Fall gleich ein anderes Problem:

    template<typename T> class DataStructure{
     T Add(T t){
      // <<save T into the underlying Datastructure>> 
      return t;
     }
    
     T Get(unsigned int Index){
      // <<return T located at index Index>>
     }
    };
    
    struct Matrix{
     float _m11,_m12,_m13,_m14;
     float _m21,_m22,_m23,_m24;
     float _m31,_m32,_m33,_m34;
     float _m41,_m42,_m43,_m44;
    };
    
    // Problem 1:
    void MyFunc(DataStructure<Matrix*> *ds){
     Matrix m;
     ds->Add(&m); // Die Matrix wird nicht kopiert, sondern lediglich der Zeiger, welche auf den Stack von MyFunc zeigt und nicht mehr gültig sein wird, sobald diese Methode verlassen wird.
    }
    
    // Scheinlösung 1:
    void MyFunc2(DataStructure<Matrix> *ds){
     Matrix m;
     ds->Add(m); // Funktioniert zwar, wird aber ganz schön viel kopiert. Es wäre mir lieber, man könnte es so lösen, dass die Matrix nur innerhalb der Methode Add von DataStructure kopiert wird und nicht zusätzlich noch bei der Parameterübergabe selbst.
    }
    
    // Problem 2:
    void MyFunc2(DataStructure<Matrix> *ds){
     Matrix m = ds->Get(2);
     m._11 = 23; // Hat keinene Einfluss auf die Matrix innerhalb der Datenstruktur, weil ich hier nur eine lokale Kopie habe. Nun müsste ich die entsprechende Matrix aus der Liste entfernen und anschliessend wieder hinzufügen. Ganz schön ineffizient.
    }
    
    // Lösung 2 (führt aber gleich wieder zu Problem 1)
    void MyFunc2(DataStructure<Matrix*> *ds){
     Matrix *m = ds->Get(2);
     m->_11 = 23; // Funktioniert, führt aber dafür wieder zu Problem 1 beim hinzufügen von Elementen...
    }
    
    // Schlechte Lösung für die oben genannten Probleme...
    void MyFunc2(DataStructure<Matrix*> *ds){
     Matrix *m = new Matrix();
     ds->Add(m); // Funktioniert, ist allerdings auch nicht besonders toll, dann 10'000de von Male ein new aufzurufen. Ganz zu schweigen davon, wer das Teil dann wieder löschen soll, aber naja... Besonders bei sehr kleinen Datenstrukturen wie bspw. Vektoren währe das kopieren vermutlich schneller, als Ständig den MemoryAllocater von Windows zu bemühen, welcher einen einzigen Semaphor für sämtliche laufenden Prozesse hat. => Synchronisations Overhead
    }
    

    So ich hoffe, ich habe das alles nicht zu verwirrend formuliert



  • Ishildur schrieb:

    ds.Add<int*>(&a); // cannot convert parameter 1 from 'int *' to 'int *&'
    

    Wenn mich nicht alles täuscht müsste das so aussehen:

    ds.Add<int&*>(&a);
    

    (also mit dem Referenzoperator** & **)



  • du machst dir unnötig viele probleme, in dem du const-correctness nicht beachtest:

    template<typename T>
    T add(const T &t)
    {
      return t;
    }
    
    int main()
    {
      int a = 12;
      int u = add(a);
      int *v = add(&a);
    
      float b = 1.f;
      float w = add(b);
      float x = add(&b);
    }
    

    sollte gehen - oder hab ich jz irgendwas zu sehr vereinfacht?

    dein problem war, dass du einen rvalue an eine referenz binden wolltest - das geht aber nicht so ohne weiteres...

    bb



  • Hei Unskilled ändere mal deinen Namen, du bist sehr wohl skilled! 😉
    Der Rückgabetyp muss dann auch noch const sein, aber ansonsten Funktionierts einwandfrei auch wenn ich noch nicht so ganz nachvollziehen kann wieso...



  • ty ;o)

    I. schrieb:

    Der Rückgabetyp muss dann auch noch const sein[...]

    Nur, wenn du ne refernz oder nen zeiger zurückgeben möchtest...

    I. schrieb:

    [...], aber ansonsten Funktionierts einwandfrei auch wenn ich noch nicht so ganz nachvollziehen kann wieso...

    naja:

    void brauche_ref(int &x)
    {
      x = 12;
    }
    
    void brauche_nix(const int &x)
    {
      /*...*/
      x;
    }
    
    int main()
    {
      brauche_ref(12); //fail...
      brauche_nix(12); //so gehts aber^^
    }
    

    ein rvalue kann eben nicht an eine non-const referenz gebunden werden, weil dann so was wie oben passieren könnte...

    bb



  • Ok, aber wie war dann das mit dem Zeiger, wieso hats denn da nicht funktioniert, das wäre doch eigentlich ein LValue gewesen oder irre ich mich da?



  • irrst dich ;o)

    void need_ref(int *&ptr)
    {
      ptr = new int(34567);
    }
    
    void need_nothing(int *ptr)
    {
      std::cout << *ptr << std.:endl;
    }
    
    int main()
    {
      int a = 123;
      need_ref(&a); //fail
      need_nothing(&a);
    }
    

    so in etwa war das mit dem ptr ;o)


Anmelden zum Antworten