operator [] Überladung



  • Ahh...
    Wie das prinzipell mit der Überladung und const funktioniert ist Dir klar?!
    Z.B. könnte ich Dich bitten eine const Überladung von S::get() zu erstellen?

    Vielleicht in diesem Minimalbeispiel:

    #include <iostream>
    
    template<typename T>
    class S {
      T m_val;
    public:
      S(const T& t)
        : m_val(t) { }
      T& get() { return m_val; }
    };
    
    using namespace std;
    
    int main(){
      S<int> s(31415);
      cout << s.get() << endl;
    
      const S<int> s1(42);
      cout << s1.get() << endl;  // kompiliert nicht!?
    }
    


  • ich stehe mit const noch ein wenig Kriegsfuss 😉
    und Überladen von Funktionen sollte wenn ich jetzt mal nicht nachlese das
    nutzen von gleichen Funktionsnamen mit unterschiedlichen deklarierten Variablen sein so das sich der Compiler die passende Funktion raussuchen kann.

    Also eigentlich so wie beim Ausgabeoperator oder ?

    zu const

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    //---------------------------------------------Aufgabe 1------------------------------------------------------------------------------
    template<class T> struct S
    {
    private:
    	T val;
    
    public:
    	S(const T t) :val(t){}  // GEAENDERT
    	S(){}
    
    	//--------------------------------------------------------------------
    
    	T& get()
    	{
    		return val;
    	}
    	const T& get() const   // EINGEFUEGT
    	{
    		return val;
    	}
    
    	void set(T t)
    	{
    		val = t;
    	}
    
    	S operator=(const T& tt)
    	{
    		val = tt;
    		return *this;
    	}
    
    	istream& operator>>(istream& is)
    	{
    		is >> val;
    		return is;
    	}
    
    	/*T& operator[](int i) // auch ein Versuch aber ohne Erforlg
    	{
    	return this.val[i];
    	/*int b = 0;
    	T* ptr = &val;
    	vector<T>c;
    	//while (*ptr){ c.push_back(val); ptr++; }
    	//cout << "0 " << *ptr << " 1 " << *ptr  << endl;
    	//ptr+=i;
    	return c[i] ;*/
    
    	T& operator =(T& x)
    	{
    		return x;
    	}
    
    };
    
    /*template<class A>
    A&  operator[](int i ,vector<A>& gv) // hier komme ich nicht weiter
    {
    	return gv[i];
    }
    
    template<class G>
    G&  operator[](const S<G> c)
    {
    	return c.get();
    }
    */
    template<class N>
    ostream& operator<<(ostream& os, vector<N>& s)
    {
        for (auto iter = s.begin(); iter != s.end(); ++iter)
    		   os << "-" << *iter;
    	return os;
    }
    
    template<class N>
    ostream& operator<<(ostream& os, S<N> c)
    {
    	os << c.get() << endl;
    	return os;
    }
    
    //---------------------------------------------Aufgabe 3------------------------------------------------------------------------------
    int main()
    {
    	vector<int>vi{ 0, 1, 2, 3, 4, 5, 6, 7 };
    	S<int>sint = 1;
    	S<char>scha = '2';
    	S<double>sdou = 1.2;
    	S<vector<int>>v(vi);
    	const S<int> ci = 9;   // EINGEFUEGT
    
    	cout << ci.get()<<endl; // EINGEFUEGT
    	cout << sint;
    	cout << scha;
    	cout << sdou;
    	cout << v;
    	// soweit so gut aber hier komme ich nicht weiter
    
    	//cout<<"Wert " << v[2]<<endl;
    
    	char ch;
    	cin >> ch;
    
    }
    


  • utass schrieb:

    ich stehe mit const noch ein wenig Kriegsfuss 😉

    Sonst hättest Du wohl kaum gepostet...

    Das mit dem S::get() hat aber sehr gut geklappt. Und ja: das mit dem Ausgabeoperator funktioniert sogut weil man ihn überladen kann.
    So "auf Kriegsfuß" kannste also nicht mit const stehen...

    Frage:
    Was soll denn der S::operator[] machen?
    Generell verstehe ich S nicht. 😞



  • Ich versuche mich nebenbei weiter an dem Operator
    aber im Moment bekomme ich die Fehlermeldung
    Operator [] muss ein nicht statischer Member sein
    😕 😕



  • S ist für mich eine Aufgabenstellung um Template zu verstehen.
    Nun habe ich die Aufgabe gehabt als Typ Vektor in S definieren so wie ich ja auch Klassen einfügen kann.
    Die Hauptaufgabe bei der ich nicht weiter komme ist das ich auf den Vector den ich in S deklariert habe Indizierten Zugriff erreichen soll.
    Damit tue ich mich schwer weil ich auch noch nicht verstanden habe wie ich einen
    2 dimensionalen Vector beschreibe und auslese.



  • utass schrieb:

    S ist für mich eine Aufgabenstellung um Template zu verstehen.
    Nun habe ich die Aufgabe gehabt als Typ Vektor in S definieren so wie ich ja auch Klassen einfügen kann.
    Die Hauptaufgabe bei der ich nicht weiter komme ist das ich auf den Vector den ich in S deklariert habe Indizierten Zugriff erreichen soll.

    Ich sehe aber keinen Vektor, den Du in S deklariert hast?!

    Das Problem ist IMHO, dass der operator[] derzeit nicht vernünftig zu implementieren ist, weil T nicht unbeding einen operator[] hat:
    Bei S<vector<char>> schon, bei S<int> nicht.

    Vielleicht soll Dein S viel eher so aussehen?!

    template<typename T>
    struct S {
      std::vector<T> val;
      //....
    };
    


  • Hm, ich verstehe deine Aufgabenstellung nicht so ganz. Deine Verwendung des Klassentemplates ist eigenartig. Ein Typ, der einzelne Variablen, z.B. ints haelt, aber auch Vektoren.
    So wie du es momentan geschrieben hast, koennen einige Operationen nicht funktionieren.
    Dein operator>> hat z.B. zwei Probleme:
    1. Er ist super merkwuerdig geschrieben. Da du ihn als Memberfunktion ausgelegt hast, muss man statt

    cin >> var;
    
    var >> cin;
    

    schreiben. Ich schaetze mal, das ist nicht das, was du willst.
    2. Fuer einen Typ, der nicht operator>> anbietet, kompiliert dein Code nicht. Das kann ok sein, vielleicht willst du ja nur diese Typen unterstuetzen. Hiermit kollidiert aber dein Vorhaben, std::vector als Typ zu verwenden. Hier solltest du dich entscheiden.

    Mein Tipp an dich: Schreibe ein neues Klassentemplate, das intern einen std::vector<T> haelt. Schreibe dann getter und setter, die den Vektor manipulieren. Wenn du das hast, kannst du das zu operator[] umschreiben.

    Edit: siehe Furble Wurbles Beitrag.



  • O Sorry der Eingabeoperator selbst ist Falsch geschrieben denn muss ich überarbeiten.

    Das Objekt S deklariere ich als Typ Vector im Zeile 92. und initialisiere es mit vi.
    Eventuell liegt ja auch da schon mein Fehler ?
    Vielleicht muss ich Ihn ja über den Eingabeoperator befüllen oder eine push_back Funktion schreiben.
    Das ist in den Aufgabenstellungen aber leider nicht ersichtlich.

    Leider ist die Aufgabe der Deklaration T val vorgegeben .
    Na gut, trotz dem vielen Dank für Deine Unterstützung ich werde mal versuchen den Eingabeoperator hin zu bekommen und dann den vector damit befüllen, vielleicht ergibt sich dann die Sache. wie bereits erwähnt ist das befüllen und lesen von vector<vector<int>> für mich ja auch noch ein bömisches Dorf und deshalb dachte ich das ich den vector vi einfach in v kopieren kann.
    Ich bin von ausgegangen das ich v[i] schreiben kann und fertig .

    🙂 Ist halt doch nicht alles so einfach 🙂



  • Puh, das verwirrt mich nur noch mehr...

    Dir geht es doch um operator[]? Jetzt schreibst du etwas von initialisieren und push_back. Das passt fuer mich nicht zusammen.

    Kannst du eine GENAUE Aufgabenstellung schreiben? Das wuerde eventuell einiges erleichtern.



  • utass schrieb:

    Leider ist die Aufgabe der Deklaration T val vorgegeben.

    Zeig mal.



  • OK ich mach mir mal die Arbeit.
    Aufgaben Kapitel 19 Vektor, Templates und Ausnahmen
    Buch Einführung in die Programmierung mit C++ Bjarne Stroustrup

    1.) Definieren Sie das Template template <class T> struct S{T val;}.

    2.) Ergänzen Sie einen Konstruktor , das Sie mit einem T-Objekt initialisieren können.

    3.) Definieren Sie Variablen der Typen S<int>,S<char>, S<double> und
    S<vector<int>>, initialisieren Sie die Variablen mit Werten Ihrer Wahl.

    4.) Lesen Sie die Werte ein und wieder aus.

    5.) Fügen Sie ein Funktions-Template get() hinzu , das eine Referenz auf val zurückliefert.

    6.) Definieren Sie get() außerhalb der Klasse.

    7.) Machen Sie val private.

    8.) Nehmen Sie sich noch einmal Aufgabe 4 vor und verwenden Sie diesmal dazu Ihr Funktions-Template get().

    9.) Fügen Sie ein Funktions-Template set() hinzu , mit dem Sie val ändern können.

    10.) Ersetzen Sie set() durch operator=(const T &).

    11.) Stellen Sie const und Nicht- const- Versionen von Operator[] bereit.

    Ich hoffe das dies weiter hilft.



  • Oh, Leute, verwirrt den/die/das utass doch nicht unnötig.
    Der zu definierende operator [] ist natürlich nur verwendbar wenn man ein T mit operator [] verwendet. Wie im Beispiel S<vector<int>> .



  • Hallo Hustbaer,

    wieso funktioniert dann T& operator[](int i)
    {
    return val[i];
    }
    nicht ?
    Kannst Du mir da bitte auf die Sprünge helfen , das ich weiter komme ?
    Ich trete schon so lange auf dieser Stelle aber finde keine Lösung der Compiler ist immer am meckern.

    BITTE 🙂



  • Ich finde die Aufgabenstellung einfach sehr merkwuerdig, das passt finde ich nicht zu Bjarne.
    Naja, wie auch immer:

    Wenn du Memberfunktionen auf die "uebliche" Weise deklarierst und definierst, werden sie non-const:

    struct S // wir vergessen mal kurz die templates
    {
        void change(int some_parameter);
    };
    

    Diese Funktion kann auch nur von non-const Instanzen von S aufgerufen werden.
    Wenn du nach dem Kopf der Funktion ein const nachstellst, gehts auch mit konstanten Objekten. Das ist hier gesucht.

    struct S // wir vergessen mal kurz die templates
    {
        void dont_change(int some_parameter) const;
                                          // ^^^^^^  Bam!
    };
    

    In konstanten Memberfunktionen darfst du das Object natuerlich auch nicht veraendern.

    Zum operator[] (und das erlaube ich mir mal, da du ja auch schon in Kapitel 19 bist):
    Wenn das schon in einer Klasse geschehen soll, in der die Anwendung eines operator[]s mal sinnvoll und mal nicht sinnvoll ist, koenntest du auch eine Spezialisierung des Klassentemplates fuer std::vector schreiben, das operator[] anbietet.

    #include <iostream>
    #include <vector>
    
    template<typename T>
    class S
    {
        public:
            S(const T& t) : t(t)
            {
            }
    
        private:
            T t;
    };
    
    template<typename T>
    class S<std::vector<T>>
    {
        public:
            S(const std::vector<T>& v) : vec(v)
            {
            }
    
            T& operator[](unsigned int i)
            {
                return vec[i];
            }
    
        private:
            std::vector<T> vec;
    };
    
    int main()
    {
        S<double> sd(3.14);
        std::vector<int> temp({1, 2, 3});
        S<std::vector<int>> v(temp);
        std::cout << v[0] << '\n';
    }
    

    wieso funktioniert dann T& operator[](int i)
    {
    return val[i];
    }
    nicht ?

    "Funktioniert nicht" ist so eine Sache. Was erhaelst du denn als Fehlermeldung? Prinzipiell sieht der code ok aus, wobei das natuerlich nur fuer Typen kompiliert, die selbst operator[] anbieten.

    Edit: Die Aufgabe ist doch sehr merkwuerdig. Was soll denn die Signatur von operator[] sein?

    template<typename T>
    class S
    {
        public:
            S(const T& t) : m_t(t)
            {
            }
    
            T operator[](int i) // das geht natuerlich nicht, T ist ja vector<irgendwas>
            {
                return m_t[i];
            }
    
            typename T::value_type operator[](int i) // ok, aber naja...
            {
                return m_t[i];
            }
    
        private:
            T m_t;
    };
    

    Das ist doch nicht so knorke. Dann lieber wie Furble Wurble es schrieb. Oder gleich eine sinnvolle Aufgabe machen.

    Wenn du operator-ueberladung ansehen moechtest, schreibe lieber eine eigene kleine vector-klasse. Das ist eine schoene uebung, in der man einiges beachten muss. Man lernt noch was ueber RAII, die Regel der Drei (bzw. Fuenf), kann viele Operatoren ueberladen, hat templates usw.



  • Moin.
    In den Errata ist die Aufgabe geändert. Wohl ein Typo.
    Hoffentlich haste nicht die Lust verloren... 🙂

    Bjarne S. schrieb:

    (+1/16/2010) pg 681: Revised chapter 19 drill:

    1-9 unchanged
    10. Replace set() with an S<T>::operator=(const T&). Hint: Much simpler than §19.2.5.
    11. Provide const and non-const versions of get();
    12-13 unchanged
    14: Bonus: Define input and output operators (>> and <<) for vector<T>'s.
    For both input and output use a { val, val, val } format.
    That will allow read_val() to also handle the S< vector<int> > variable.

    http://www.stroustrup.com/Programming/errata2p.html



  • OK, an den Rückgabetypen hab' ich nicht gedacht.

    In C++11 sollte es kein Problem sein, weil man -> auto& verwenden kann.

    auto operator[](size_t i) -> auto&
         { 
         	return val[i];
         }
    

    In C++03 müsste man die Funktion auf z.B. Container die T::value_type definieren einschränken:

    typename T::value_type operator[](size_t i)
         { 
         	return val[i];
         }
    

    Wobei der aktuell von ideone für C++14 verwendete Compiler hier der Meinung ist die Funktion sofort instanzieren zu müssen, was dann natürlich für Typen wie int bei T::value_type kracht.

    prog.cpp: In instantiation of 'struct S<int>':
    prog.cpp:25:15:   required from here
    prog.cpp:15:29: error: 'int' is not a class, struct, or union type
          typename T::value_type operator[](size_t i)
    

    Sollte das nicht explizit über SFINAE erlaubt sein?
    So lange operator [] nirgends verwendet wird, besteht ja keine Notwendigkeit dass T::value_type was sinnvolles ergibt oder auch nur existiert.

    Oder hab' ich da was falsch verstanden/falsch in Erinnerung?

    EDIT: Da mein Beitrag hier ne neue Seite angefangen hat...
    Furble Wurble hat die Erklärung gefunden - die Aufgabe mit operator [] war schlicht ein Fehler: https://www.c-plusplus.net/forum/p2443845#2443845



  • Hallo Leutz,
    Danke Furble Wurble dann kann ich die Aufgabe ja getrost auslassen.
    Ich wusste gar nicht das es so etwas wie eine Korrektur für das Buch gibt.
    Leider kann ich auch kein Englisch, so das ich mich auf der Seite belesen könnte aber ich werde mir die Seite für spätere Eventualitäten abspeichern.

    Danke auch allen anderen Helferlein.

    Ich werd dann mal weiter machen.
    Lust verlieren ist nicht eher mach ich ne Pause und lass sacken.
    Ich hab hier 4 Bücher zu liegen aber manchmal fehlt einen dann doch die Möglichkeit mit einen darüber zu reden wenn man nicht weiter kommt.

    Bis auf ein nächstes mal nun hol ich erst mal nen Eisbecher 😃 😃

    Guido



  • utass schrieb:

    aber manchmal fehlt einen dann doch die Möglichkeit mit einen darüber zu reden wenn man nicht weiter kommt.

    Rettet dem Dativ! 😉


Anmelden zum Antworten