[c++][template][operatoren] linker findet Methoden nicht

eclarion

Grünschnabel
Hi,
ich bin noch recht neu in C++ und habe mich mal an Templates herangewagt.

Dazu habe ich eine Klasse Vector3D erstellt die einen 3D - Vektor darstellt und
die Operationen + und * überläd. Diese Klasse soll generisch sein, damit ich
sowohl double als auch complexe Komponenten nutzen kann.

Ich kompiliere unter Gentoo mit g++-4.1.2.

Beim kompilieren tritt folgender Fehler auf:

Code:
g++ a17.cpp -o a17
vector3d.h:61: warning: friend declaration 'std::ostream& operator<<(std::ostream&, Vector3D<T>)' declares a non-template function
vector3d.h:61: warning: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) -Wno-non-template-friend disables this warning
/tmp/ccQ5XYPB.o: In function `main':
a17.cpp:(.text+0x226): undefined reference to `operator<<(std::basic_ostream<char, std::char_traits<char> >&, Vector3D<double>)'
a17.cpp:(.text+0x5d0): undefined reference to `operator<<(std::basic_ostream<char, std::char_traits<char> >&, Vector3D<std::complex<double> >)'
collect2: ld returned 1 exit status

Offenbar generiert der Compiler also nicht die geforderten Methoden zur Ausgabe aus ihren generischen Deklarationen, nur kann ich nicht herausfinden wieso !?

Hier mal der Code:

a17.cpp (Hauptprogramm)
Code:
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>
#include <cstdlib>
#include <complex>

#include "vector3d.h"

using namespace std;

int main(int argc, char *argv[])
{
  cout << "Mit Double Werten: " << endl;
  Vector3D<double> a(3.0,3.0,3.0);
  Vector3D<double> b(2.0,2.0,2.0);
  cout << "Multipliziert: " << (a*b) << endl;
  cout << "Addiert: " << (a+b) << endl << endl;

  cout << "Mit Complexen Werten: " << endl;
  Vector3D<complex<double> > c((1.0, 1.5),(2.0, 4.0),(3.0, 5.0));
  Vector3D<complex<double> > d((4.0, 2.5),(5.0, 3.0),(6.0, 4.5));
  cout << "Multipliziert: " << (c*d) << endl;
  cout << "Addiert: " << (c+d) << endl << endl;

  return EXIT_SUCCESS;
}

vector3d.h
Code:
#ifndef VECTOR3D_H
#define VECTOR3D_H

#include <iostream>


using namespace std;

template<class T> class Vector3D{

	private:
		T vector[3];

	public:

	/**
	 * Standardkonstruktor, initialisiert einen Vektor mit den Koordinaten (0,0,0)
	 */
	Vector3D();

	/**
	 * Konstruktor, der einen Vektor an vorgegebenen Koordinaten initialisiert.
	 */
	Vector3D(T x, T y, T z);

	/**
	 * Ueberlaed den +-Operator so, dass er die Addition fuer zwei Vektoren ausfuehrt.
	 */
	Vector3D<T> operator+ (Vector3D<T> vec);

	/**
	 * Ueberlaed den *-Operator so, dass er die skalare Multiplikation ausfuehrt.
	 */
	T operator* (Vector3D<T> vec);

	/**
	 * Ueberlaed den Ausgabeoperator damit er Vector3D Objekte im format (x,y,z) ausgibt.
	 */
	friend ostream& operator<< (ostream &os, Vector3D<T> vec);



	/**
	* Getter-/Setter der Variablen.
	*/
	void setVector(T x, T y, T z)
	{
		vector[0] = x;
		vector[1] = y;
		vector[2] = z;
	};

	T *getVector()
	{
		
		return vector;
	};

	//Desktruktor
    ~Vector3D();

};

#include "vector3d.cpp"

#endif


vector3d.cpp
Code:
#include "vector3d.h"

template<class T> Vector3D<T>::Vector3D()
{
	vector[0] = 0;
	vector[1] = 0;
	vector[2] = 0;
}


template<class T> Vector3D<T>::Vector3D(T x, T y, T z)
{
	vector[0] = x;
	vector[1] = y;
	vector[2] = z;
}

template<class T> Vector3D<T>::~Vector3D(){}

template<class T> Vector3D<T> Vector3D<T>::operator+ (Vector3D<T> vec)
{
	T *co = vec.getVector();
	
	return *(new Vector3D<T>(vector[0]+co[0], vector[1]+co[1], vector[2]+co[2]));
}

template<class T> T Vector3D<T>::operator* (Vector3D<T> vec)
{
	T *co;
        co = vec.getVector();
	return (vector[0]*co[0] + vector[1]*co[1] + vector[2] * co[2]);
}

template<class T> ostream& operator<< (ostream &os, Vector3D<T> vec)
{
	T *co = vec.getVector();
	os << "(" << co[0] << ", " << co[1] << ", " << co[2] << ")";
	return os;
}

Über Antwort würde ich mich sehr freuen.

Grüße

Alex
 
Hi.
vector3d.h
Code:
using namespace std;
Das sollte man in einer Header Datei nicht schreiben, da es dann in allen anderen Dateien die diese Header Datei einbinden auch eingefügt wird.
Code:
	/**
	 * Ueberlaed den Ausgabeoperator damit er Vector3D Objekte im format (x,y,z) ausgibt.
	 */
	friend ostream& operator<< (ostream &os, Vector3D<T> vec);
Mit dieser Anweisung wird überhaupt nichts überladen. Es ist lediglich eine Aussage, das wenn es einen solchen Operator gibt, und das dieser als "Freund" auch entsprechenden Zugriff auf die Klassenmitglieder hat.

Ansonsten hat doch der Compiler bereits erklärt warum das Problem auftritt und wie man es beseitigen kann:
Code:
g++ a17.cpp -o a17
vector3d.h:61: warning: friend declaration 'std::ostream& operator<<(std::ostream&, Vector3D<T>)' declares a non-template function
vector3d.h:61: warning: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)

Also: Diese Deklaration deklariert eine nicht-template Funktion - du willst allerdings eine template-Funktion als friend deklarieren.

Wenn man das nicht will, muss man dafür sorgen, dass das Funktions-Template bereits vorher definiert ist und <> nach dem Funktionsnamen einfügen.

C++:
template<class T> class Vector3D;

template<class T>
ostream&
operator<< (ostream &os, Vector3D<T> vec);

template<class T> class Vector3D{
  ...

  /**
   * Deklariert den Ausgabeoperator der Vector3D Objekte im format (x,y,z) ausgibt
   * als friend.
   */
  friend ostream& operator<< <>(ostream &os, Vector3D<T> vec);
...
};
Gruß
 
Zurück