C++ programmers, help me please!

I used to know this, but too much Java has stunted me and I can’t find the answer anywhere online.

I’m writing a templated class which I would like to override the “<<” operator so I can use it via the standard output streams. I’ve defined the operator to be a friend of my class in the class definition and I’ve overloaded the operator. This compiles fine, but when I come to use it, it won’t link! I get the error:



1>angle.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl mulligan::maths::operator<<(class std::basic_ostream<char,struct std::char_traits<char> > const &,class mulligan::maths::angle<float> const &)" (??6maths@mulligan@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@ABV23@ABV?$angle@M@01@@Z) referenced in function _main
1>Debug\SoftwareEngine.exe : fatal error LNK1120: 1 unresolved externals


And I cannot work out why.
Here’s the definition and declaration of the relevant function:



friend std::ostream& operator << (const std::ostream& stream, const angle<t>& a);


and



		template<typename t>
		std::ostream& operator << (const std::ostream& stream, const angle<t>& a)
		{
			switch(a._current_represenation)
			{
			case ANGLE_TYPE_DEGREES:
				stream << "mulligan.maths.angle<> : " << a._angle << " degrees.";
				break;
			case ANGLE_TYPE_RADIANS:
				stream << "mulligan.maths.angle<> : " << a._angle << " radians.";
				break;
			}
			return stream;
		}


Any help is appreciated, thanks.

The body of a template function has to be included in any source files that you intend to use it in. Do you have it sitting in its own file like any other code?

btw, if you’re only using the template argument to differentiate between degrees and radians, it’s really overkill. You could have a class, angle, with a pure virtual function print(), and an operator << that takes an angle a and just calls a.print(). Have subclasses for each representation, and you’re good to go. That gets you around the template link errors quite handily.

Thanks. I originally had the body of the operator in my angle class source file. I moved it out to the angle class header, but it still gives the same linking error. Is this what you meant?

BTW: the template parameter specifies what data type the angle is stored as. Overkill, I know, but I want to get used to templates again after using Java fopr so long.

That is the right approach. If you have precompiled headers turned on, try doing a full rebuild.

One problem I see is that the input stream is declared a const ostream&, while the return value is a (non-const) ostream&. This ought to give you a compile-time error, AFAICT, not the link error you’re getting now (something like "invalid initialization of reference of type ‘std:: ostream&’ from expression of type ‘const std::basic_ostream’ "). The input should be a non-const ostream&, since writing to an ostream changes its internal state.

Is the template function defined in the correct namespace (mulligan::maths:: )? Could you show an example of the usage of operator<< that’s breaking it?

One more thing you could try: remove the templating code (replace the templated classes and functions with a single instantiation) and see if it works then. This will tell you if your problem is with one of the template specifiers or with the basic class structure, and the errors are sometimes easier to decipher with less templating.

I agree with ultrafilter on the full rebuild if there are precompiled headers, too.

Do you have the definition of the ostream& operator before your class definition? e.g.



template <class T> class angle;

std::ostream& operator << (const std::ostream& stream, const angle<t>& a)
{
...
}

template <class T> class angle
{
....
  friend std::ostream& operator << (const std::ostream& stream, const angle<t>& a);
}


You need to have the function visible before you can declare it a friend. (My understanding is) this is required by the standard, but wasn’t enforced in earlier compilers.

That would cause a compiler error, not a linker one.

From a C++ FAQ for the Sun compiler (bolding mine)

Unfortunately, +MDI, I don’t think this will solve your problem. I had the same problem with my code when compiling on the Sun platform, and was able to fix it with the help of the link above. I thought I had it working on my PC compiler as well, but apparently I just wasn’t testing that bit of code. At least I’m able to reproduce your error. :wink:

Got it (I thought I had this working once). You need template <class T> in front of the friend declaration:



template <class T> class angle
{
....
  template <class T>
  friend std::ostream& operator << (const std::ostream& stream, const angle<T>& a);
}


On my Visual Studio .NET 2003 compiler, it doesn’t matter if the definition is before the class definition.

Sorry it’s taken so long to get back to you. I appreciate the input, and I’ve tried a few things which have been suggested, and I’ve finally got it working correctly.

FWIW, I’m using MS’s latest compiler (MS C++ 2005 Beta 2). It works exactly as ZenBeam’s link states, apart from I needed to swap the global namespace lookup for mulligan::maths.

The template line that ZenBeam has before his friend operator declaration is redundant on the new compiler (it compiles, links and runs fine without it).

Thanks for all the suggestions and advice.