friend Methoden in Template Klassen

Schnelle objektorientierte, kompilierende Programmiersprache.
MiCsoft
Beiträge: 18
Registriert: So Nov 08, 2020 8:18 pm

friend Methoden in Template Klassen

Beitrag von MiCsoft » Mo Jan 18, 2021 11:25 am

Hallo zusammen,

ich hab gerade ein Problem mit meiner List<T> Klasse. Würde dort sehr gerne eine Output Operation zur Verfügung stellen. Diese realisiere ich über friend ostream &operator<<(ostream &os, ListNode &other);
Nun habe ich aber das Problem das ich in der Header Datei nicht ListNode<T> schreiben kann. Weil er das T nicht kennt.

Weiß jemand wie man in Template Klassen friend Operatoren implementiert bekommt?

Hier mal mein Code zusammengefasst =)

Code: Alles auswählen

#ifndef LISTNODE_H_
#define LISTNODE_H_

#include <memory>
#include <iostream>

using namespace std;

template<class T>
class ListNode {
private:
	class Node {
	private:
		T value;
		unique_ptr<Node> next;
	public:
		Node(T value = { }, unique_ptr<Node> next = nullptr) :
				value(value), next(move(next)) {	}
		unique_ptr<Node>& getNext()  { .... }
		void setNext(unique_ptr<Node> next) { .... }
		T getValue() const { .... }
		void setValue(T value) { ... }
	};
	unique_ptr<Node> anfang;
  	void recInsert(unique_ptr<Node> &s, T value);
	void rekCopy(const unique_ptr<Node> &pAct);
	void recPrint(const unique_ptr<Node> &s);
public:
	ListNode();
	virtual ~ListNode() = default;
	ListNode(const ListNode<T> &other);
	ListNode(ListNode<T> &&other);
	ListNode<T>& operator=(const ListNode<T> &other);
	ListNode<T>& operator=(ListNode<T> &&other);
	void insert(T value);
	void print();
        friend ostream &operator<<(ostream &os, ListNode<T> &other);
};

//ostream &operator<<(ostream &os, ListNode<T> &other) {
//	return os;
//}

#endif /* LISTNODE_H_ */
Hoffe das ganze ist so weit verständlich :-)
Natürlich ist in der ListNode Klasse noch mehr drin, Konstruktoren etc. habe ich raus genommen. Die void print() Mehtode macht derzeit das, was der << Operator später machen soll =D

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8859
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: friend Methoden in Template Klassen

Beitrag von Xin » Mo Jan 18, 2021 11:57 am

MiCsoft hat geschrieben:
Mo Jan 18, 2021 11:25 am
ich hab gerade ein Problem mit meiner List<T> Klasse. Würde dort sehr gerne eine Output Operation zur Verfügung stellen. Diese realisiere ich über friend ostream &operator<<(ostream &os, ListNode &other);
Nun habe ich aber das Problem das ich in der Header Datei nicht ListNode<T> schreiben kann. Weil er das T nicht kennt.
Dann stell ihm T doch mal vor. :-)

Code: Alles auswählen

template< typename T >
ostream &operator<<(ostream &os, ListNode<T> &other) {
	return os;
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

MiCsoft
Beiträge: 18
Registriert: So Nov 08, 2020 8:18 pm

Re: friend Methoden in Template Klassen

Beitrag von MiCsoft » Mo Jan 18, 2021 2:04 pm

Stimmt so einfach kann es gehen.

Jetzt habe ich aber noch 2 weitere Probleme :-(
Zum einen nörgelt die main.cpp nun rum mit folgendem Fehler:
Warnung: undefinierter Verweis auf »operator<<(std::ostream&, ListNode<int>&)«
In der Klasse zeigt er mir bei der friend Methode auch folgendes an:
friend declaration ‘std::ostream& operator<<(std::ostream&, ListNode<T>&)’ declares a non-template function [-Wnon-template-friend]
Des weiteren begreife ich gerade nicht wie ich das mit einem unique_ptr hin bekomme, meine Ausgabe.
Denn so kann es ja nicht gehen.

Code: Alles auswählen

template<class T>
ostream& operator<<(ostream &os, ListNode<T> &other) {
//	while (other.anfang != nullptr) {
//		os << other.anfang->getValue() << " ";
//		other.anfang = other.anfang->getNetx();
//	}

	return os;
}
Den other.anfang Pointer (unique) müsste man zwischen speichern als tmp um dann mit einer while - Schleife weiter zu schalten und sich die Werte ausgeben lassen. Doch das geht ja so einfach mit unique_ptr nicht =(

Weiß jemand weiter?

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8859
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: friend Methoden in Template Klassen

Beitrag von Xin » Mo Jan 18, 2021 4:14 pm

MiCsoft hat geschrieben:
Mo Jan 18, 2021 2:04 pm
Stimmt so einfach kann es gehen.

Jetzt habe ich aber noch 2 weitere Probleme :-(
Zum einen nörgelt die main.cpp nun rum mit folgendem Fehler:
Warnung: undefinierter Verweis auf »operator<<(std::ostream&, ListNode<int>&)«
In der Klasse zeigt er mir bei der friend Methode auch folgendes an:
friend declaration ‘std::ostream& operator<<(std::ostream&, ListNode<T>&)’ declares a non-template function [-Wnon-template-friend]
Bitte versuch:

Code: Alles auswählen

	friend std::ostream& operator <<<> (std::ostream&, ListNode<T> const &);
Das <> hinter dem Funktionsnamen sagt dem Compiler, dass es sich um eine Template-Funktion handelt.
MiCsoft hat geschrieben:
Mo Jan 18, 2021 2:04 pm
Des weiteren begreife ich gerade nicht wie ich das mit einem unique_ptr hin bekomme, meine Ausgabe.
Denn so kann es ja nicht gehen.

Code: Alles auswählen

template<class T>
ostream& operator<<(ostream &os, ListNode<T> &other) {
//	while (other.anfang != nullptr) {
//		os << other.anfang->getValue() << " ";
//		other.anfang = other.anfang->getNetx();
//	}

	return os;
}
Den other.anfang Pointer (unique) müsste man zwischen speichern als tmp um dann mit einer while - Schleife weiter zu schalten und sich die Werte ausgeben lassen. Doch das geht ja so einfach mit unique_ptr nicht =(

Weiß jemand weiter?
Du kannst den Unique-Pointer nicht kopieren, aber Du kannst eine Zeiger darauf setzen.

Code: Alles auswählen

template<class T>
ostream& operator<<(ostream &os, ListNode<T> &other) {
	unique_ptr< Node > * ptr = &other.Anfang;

	while ( ptr ) {
		os << (*ptr)->getValue() << " ";
		ptr = &(*ptr)->getNetx();
	}

	return os;
}
So richtig schön ist das nicht... :-|
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

MiCsoft
Beiträge: 18
Registriert: So Nov 08, 2020 8:18 pm

Re: friend Methoden in Template Klassen

Beitrag von MiCsoft » Mo Jan 18, 2021 7:11 pm

Bei mir nörgelt er nur rum.
Deswegen habe ich das ganze jetzt einfach direkt in die Klasse geschrieben:

Code: Alles auswählen

	friend std::ostream& operator << (std::ostream& os, ListNode<T> const &other) {
		unique_ptr< Node > *ptr = &other.anfang;

				while ( ptr ) {
					os << (*ptr)->getValue() << " ";
					ptr = &(*ptr)->getNext();
				}

			return os;
	}
Nun beschwert er sich noch über den

Code: Alles auswählen

		unique_ptr< Node > *ptr = &other.anfang;
error: invalid conversion from ‘const std::unique_ptr<ListNode<int>::Node, std::default_delete<ListNode<int>::Node> >*’ to ‘std::unique_ptr<ListNode<int>::Node, std::default_delete<ListNode<int>::Node> >*’ [-fpermissive]

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8859
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: friend Methoden in Template Klassen

Beitrag von Xin » Di Jan 19, 2021 8:47 am

MiCsoft hat geschrieben:
Mo Jan 18, 2021 7:11 pm
Bei mir nörgelt er nur rum.
Naja, das ist ein bisschen eine Frage der Perspektive. Eigentlich bewahrt er Dich nur davor Programmierfehler zu machen und das ist bei großen Projekten ein Feature, für das ich sehr dankbar bin. :-D
MiCsoft hat geschrieben:
Mo Jan 18, 2021 7:11 pm
Deswegen habe ich das ganze jetzt einfach direkt in die Klasse geschrieben:
Welchen Compiler nutzt Du?
In der Klasse wird das friend überflüssig.
MiCsoft hat geschrieben:
Mo Jan 18, 2021 7:11 pm

Code: Alles auswählen

	friend std::ostream& operator << (std::ostream& os, ListNode<T> const &other) {
		unique_ptr< Node > *ptr = &other.anfang;
Nun beschwert er sich noch über den

Code: Alles auswählen

		unique_ptr< Node > *ptr = &other.anfang;
error: invalid conversion from ‘const std::unique_ptr<ListNode<int>::Node, std::default_delete<ListNode<int>::Node> >*’ to ‘std::unique_ptr<ListNode<int>::Node, std::default_delete<ListNode<int>::Node> >*’ [-fpermissive]
Naja, da hat er recht. Du übergibst ein unveränderliches (const) ListNode<T> & und willst dann daraus einen Zeiger auf ein veränderliches unique<Node> haben. Wenn das große Ding aber unveränderlich ist, dann kann ein Element daraus nicht veränderlich sein. Und das sagt die Fehlermeldung mit Typinformationen aus: Unerlaubte Übertragung von const Typ * zu Typ *.

Code: Alles auswählen

		unique_ptr< Node > const *ptr = &other.anfang;
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

MiCsoft
Beiträge: 18
Registriert: So Nov 08, 2020 8:18 pm

Re: friend Methoden in Template Klassen

Beitrag von MiCsoft » Di Jan 19, 2021 11:46 am

Naja, das ist ein bisschen eine Frage der Perspektive. Eigentlich bewahrt er Dich nur davor Programmierfehler zu machen und das ist bei großen Projekten ein Feature, für das ich sehr dankbar bin.
Das stimmt, ich komme von Java und da nörgelt der Compiler noch mehr ;-) Das finde ich auch so sehr sehr gut. Dagegen ist C/C++ wie ein Käse, durchlöchert :lol: Man muss einfach aufpassen und genau wissen was man macht :!:
Welchen Compiler nutzt Du?
In der Klasse wird das friend überflüssig.
gcc Pialekt 11
Wenn ich das friend weg lasse kommt erneut ein Fehler:

Code: Alles auswählen

‘std::ostream& ListNode<T>::operator<<(std::ostream&, const ListNode<T>&)’ must take exactly one argument
So gibt es nun kein Fehler doch es kommt auch keine Ausgabe.

Code: Alles auswählen

friend ostream& operator << (ostream& os, ListNode<T> const &other) {
		unique_ptr< Node > const *ptr = &other.anfang;
				while ( ptr ) {
					os << (*ptr)->getValue() << " ";
					ptr = &(*ptr)->getNext();
				}

			return os;
	}
Das meine Liste vernünftig arbeitet sehe ich anhand der print() Methode die ich in der Klasse geschrieben habe. Dort gibt er mir genau die Knoten aus die in der Liste sind.

Der Witz ist auch wenn ich in der Methode vorher ein cout und in der while Schleife ein cout mache. Passiert nichts, nur wenn ich in der Schleife ein << endl; mache gibt er mir alles aus :roll:

Code: Alles auswählen

friend ostream& operator << (ostream& os, ListNode<T> const &other) {
		unique_ptr< Node > const *ptr = &other.anfang;
		cout << "Test";
				while ( ptr ) {
					cout << "Test" << endl;
					os << (*ptr)->getValue() << " ";
					ptr = &(*ptr)->getNext();
				}

			return os;
	}
Das bedeutet das ptr != nullptr ist und eigentlich alles richtig läuft. Denke es liegt mal wieder am outputstream =( Hast du vielleicht noch eine Idee?
Ich verstehe auch nicht wieso ich ein const Variable in der Schleife verändern darf =D Dachte const setzt man 1x danach darf man diese nicht mehr verändern.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8859
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: friend Methoden in Template Klassen

Beitrag von Xin » Di Jan 19, 2021 12:02 pm

MiCsoft hat geschrieben:
Di Jan 19, 2021 11:46 am
Naja, das ist ein bisschen eine Frage der Perspektive. Eigentlich bewahrt er Dich nur davor Programmierfehler zu machen und das ist bei großen Projekten ein Feature, für das ich sehr dankbar bin.
Das stimmt, ich komme von Java und da nörgelt der Compiler noch mehr ;-) Das finde ich auch so sehr sehr gut. Dagegen ist C/C++ wie ein Käse, durchlöchert :lol: Man muss einfach aufpassen und genau wissen was man macht :!:
Wenn ich C++ unterrichte, habe ich eine andere Perspektive. Ich bringe den Leuten bei, was sie nicht machen dürfen. Alles andere dürfen sie machen. Heißt ich bereite sie darauf vor auf einem Mienenfeld umherzuhüpfen, ohne auf die Mienen zu treten. Aber ansonsten dürfen sie sich da frei bewegen.
Die meisten Menschen lernen, was sie machen dürfen. Sie stecken einen Weg ab, wie man das Mienenfeld durchqueert. Aber wehe das Ziel liegt woanders.
MiCsoft hat geschrieben:
Di Jan 19, 2021 11:46 am
Welchen Compiler nutzt Du?
In der Klasse wird das friend überflüssig.
gcc Pialekt 11
Pialekt?
MiCsoft hat geschrieben:
Di Jan 19, 2021 11:46 am
Wenn ich das friend weg lasse kommt erneut ein Fehler:

Code: Alles auswählen

‘std::ostream& ListNode<T>::operator<<(std::ostream&, const ListNode<T>&)’ must take exactly one argument
Stimmt... das Listnode kannst Du weglassen, das ist dann ja this. Allerdings auch das erste Argument... lass das friend mal. :-D
MiCsoft hat geschrieben:
Di Jan 19, 2021 11:46 am
Das bedeutet das ptr != nullptr ist und eigentlich alles richtig läuft. Denke es liegt mal wieder am outputstream =( Hast du vielleicht noch eine Idee?
Ich verstehe auch nicht wieso ich ein const Variable in der Schleife verändern darf =D Dachte const setzt man 1x danach darf man diese nicht mehr verändern.
Die Streams werden nicht Buchstabe für Buchstabe ausgegeben, sondern immer dann wenn der Buffer voll ist oder man das explizit wünscht.

Code: Alles auswählen

ostream.flush();
vor dem Return einfügen.
Wenn der ostream ein std::endl sieht flusht er automatisch.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

MiCsoft
Beiträge: 18
Registriert: So Nov 08, 2020 8:18 pm

Re: friend Methoden in Template Klassen

Beitrag von MiCsoft » Di Jan 19, 2021 1:26 pm

Wenn ich C++ unterrichte, habe ich eine andere Perspektive. Ich bringe den Leuten bei, was sie nicht machen dürfen. Alles andere dürfen sie machen. Heißt ich bereite sie darauf vor auf einem Mienenfeld umherzuhüpfen, ohne auf die Mienen zu treten. Aber ansonsten dürfen sie sich da frei bewegen.
Die meisten Menschen lernen, was sie machen dürfen. Sie stecken einen Weg ab, wie man das Mienenfeld durchqueert. Aber wehe das Ziel liegt woanders.
Ja das stimmt schon. Doch wenn man gar kein Mienenfeld hat, lässt es sich doch sicherlich netter umherlaufen :D
So sehe ich das eben auch ;-) Man sollte aber eben auch beide Seiten kennen und sich auch mal mit anderem Beschäftigen als mit seiner Komfortzone ;)

gcc Compiler Dialekt Standard 11.

Inzwischen habe ich ehrlich gesagt auch mein Hirn ausgeschaltet :roll: Da ich mich erst mit Templates und Operatoren beschäftigt habe, dachte ich naja so schwer kann es nicht sein beides nun zu verbinden =D

So sieht die .h jetzt gut aus.

Code: Alles auswählen

ostream& operator << (ostream& os) {
		unique_ptr< Node > const *ptr = &anfang;
				while ( ptr ) {
					os << (*ptr)->getValue() << " ";
					ptr = &(*ptr)->getNext();
				}

			return os;
	}
flush() brauch ich das auch unter Linux? Dachte das bräuchte ich unter Linux (Ubuntu) gar nicht =D

Nur habe ich ja jetzt das Problem das ich cout << ListNode nicht schreiben kann =(
no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘ListNode<int>’)
Hab es auch wieder mit dem Prototyp versucht doch da weiß ich nicht mal wie ich den unique_ptr vernünftig hingeschrieben bekomme. Da er die Innere Klasse Node nicht kennt muss ich diese ja mit angeben also so:
ListNode::Node doch da kommen dann wieder 100 Fehler =(

so hatte ich es außerhalb der .h

Code: Alles auswählen

	friend ostream& operator << (ostream& os, ListNode<T> const &other); //Prototype in der .h


template<class T>
ostream& operator << (ostream& os, ListNode<T> const &other) {
		unique_ptr< ListNode::Node > const *ptr = &other.anfang;
				while ( ptr ) {
					os << (*ptr)->getValue() << " ";
					ptr = &(*ptr)->getNext();
				}

			return os;
	}
emplate argument 1 is invalid
unique_ptr< ListNode::Node > *ptr = &other.anfang;

MiCsoft
Beiträge: 18
Registriert: So Nov 08, 2020 8:18 pm

Re: friend Methoden in Template Klassen

Beitrag von MiCsoft » Di Jan 19, 2021 1:30 pm

Okay so geht es nun.
Wieso ich in der while-Schleife flush nutzen muss ist mir auch nicht klar.
Hab es vor dem retunr versucht doch dann ging es nicht. Dann habe ich noch 1x flush vor der while Schleife gemacht =D doch das brachte auch nix.
So geht es nun:

Code: Alles auswählen

	ostream& operator << (ostream& os) {
		unique_ptr< Node > const *ptr = &anfang;
				while ( ptr ) {
					os << (*ptr)->getValue() << " ";
					os.flush();
					ptr = &(*ptr)->getNext();
				}
			return os;
	}
und Aufrufen muss ich es auch extrem "unschön":

Code: Alles auswählen

	l1.operator<<(cout);

Antworten