Click to See Complete Forum and Search --> : global template function problem


danielsbrewer
February 27th, 2003, 11:23 AM
Hi there,

I am trying to provide a global function to be used in quite a few classes but I just keep getting linker errors (this is using gcc).
My header file looks like this:
//A simple streamcasting TEMPLATE function

#ifndef _STREAMCAST_H_
#define _STREAMCAST_H_

#include <strstream>
#include <iostream>


template <class Type>
std::string stream_cast( Type const& );

#endif

and my source file like this:
#include "stream_cast.h"
#include <strstream>
#include <iostream>

using namespace std;

template <class Type>
string stream_cast( Type const& from )
{
strstream stream;
string to;
stream << from;
stream >> to;
return to;
}

I seem to get linker errors if I try to call this function even though I am definitely including the header file. Examples of linker error:
This line (where i is an unsigned int):

plot_command+=", \'\' u 1:"+stream_cast(i+1);

produces this

ld: Undefined symbols:
std::basic_string<char, std::char_traits<char>, std::allocator<char> > stream_cast<unsigned>(unsigned const&)

AND (where example is a double)
string title;
title=title+stream_cast(example);

produces this

ld: Undefined symbols:
stream_cast(double const&)

Its weird because it works fine if you include it in one of the class source files and only call it from that source file.

Thanks

jfaust
February 27th, 2003, 11:28 AM
You need to inline all the template code in the header file.

Jeff

danielsbrewer
February 27th, 2003, 11:45 AM
OK.
I have tried that but I still get the same results.
I have made my source file blank and changed my header file to:

#ifndef _STREAMCAST_H_
#define _STREAMCAST_H_

#include <strstream>
#include <iostream>


template <class Type>
inline std::string stream_cast( Type const& from)
{
std::strstream stream;
std::string to;
stream << from;
stream >> to;
return to;
}
#endif

But the same problems arise. Interestingly if in the first example i gave I change an unsigned int to an int it seems to work, but still fails with the double.

very confusing

jfaust
February 27th, 2003, 12:01 PM
This works on VC++ 6.0:


#include <strstream>
#include <iostream>
#include <string>

template <class Type>
inline std::string stream_cast( Type const& from)
{
std::strstream stream;
std::string to;
stream << from;
stream >> to;
return to;
}

int main()
{
double d = 2.5;
std::cout << stream_cast(d);
return 0;
}


Make sure you don't have the orginal source file in the project and make sure everyting relying on the header file is rebuilt.

Jeff

Graham
February 27th, 2003, 12:47 PM
Slightly simpler version:

template <class Type>
inline std::string stream_cast( Type const& from)
{
std::strstream stream;
stream << from;
return stream.str();
}

Philip Nicoletti
February 27th, 2003, 01:05 PM
Just a small note, if your compiler supports it you should
use stringstream instead. strstream is deprecated.

PaulWendt
February 27th, 2003, 01:42 PM
I may be wrong about this ... but I believe that strstream::str()
returns a char* that won't be delete'd unless the programmer
calls freeze before the strstream object goes out of scope.
It has some weird behavior like that ... and that's just one of the
many reasons that people recommend you use stringstream :)

Philip Nicoletti
February 27th, 2003, 01:56 PM
According to Josuttis, strstream::str() calls the member function
freeze() implicitly. However, it does not automatically
append a string termination character ('\0') - you need
to do it explicitly (std::ends)

PaulWendt
February 27th, 2003, 03:01 PM
Yeah that's it :) On that same page [650] check out #1:

Beause ownership of the memory is transferred to the caller,
unless the stream was initialized with a buffer of fixed size, the
character sequence has to be released. However, there is no
guarantee how the memory was allocated, thus is is not always
safe to release it using delete[]. Your best bet is to return the
memory to the stream by calling the member function freeze()
with the argument false


This is what strstream does NOT do. Josuttis gives some
examples for strstream usage:


std::ostrstream buffer;
buffer << "float X: " << x << std::ends;
char* s = buffer.str();
foo(s);

buffer.freeze(false);


Without that buffer.freeze(false), there would be a memory leak.
That's all I was really implying in my last post. This only helps to
reinforce your and Graham's argument to not use strstream :)

--Paul

Graham
February 27th, 2003, 03:29 PM
Actually, I think I was being slack and meant std::ostringstream. std::ostringstream::str() returns a std::string, of course. In my defence, I've been out of work for a while now, so my reference sources are a bit thin.....

PaulWendt
February 27th, 2003, 04:21 PM
I'm sorry. I wasn't trying to make light of your post or anything;
I was just telling the original poster about the disadvantages of
strstream. Anyway, it's all water under the bridge now :)

--Paul