Click to See Complete Forum and Search --> : Class template operator instantiation


LSimao
January 17th, 2006, 03:46 PM
Hi!

I'm using the following

class MyOut {
template<typename T> operator<<(T value);
}
Now I need to instantiate some implementations but
template operator<< <int>(int value);gives a compiler error.

So, how can I instantiate class template operators?

cilu
January 17th, 2006, 03:57 PM
Should we guess what is the error message?

LSimao
January 17th, 2006, 04:07 PM
No, you shouldn't...



class MyOut {
template<typename T> MyOut& operator<<(T value);
template MyOut& operator<< <int>(int value);
}


Returns this beautifull list:

error C2143: syntax error : missing ';' before '<'
error C2530: '<<' : references must be initialized
error C2059: syntax error : '<'
error C2238: unexpected token(s) preceding ';'

The question is: syntax is not correct!!! What's the correct syntax or how can I instantiate such operators?

cilu
January 17th, 2006, 04:25 PM
Like this:

template <typename T>
class MyOut {
MyOut& operator<<(T value);
};

template <typename T>
MyOut<T>& MyOut<T>::operator<<(T value)
{
// ...
}

LSimao
January 17th, 2006, 04:33 PM
That's not my target!!!

With your example I could have a MyOut for every kind of type, which acepts THAT kind of object in operator<<.
What I want is a single MyOut which acepts any kind of object in operator<<.

No multiple classes, but multiple operators.

I found one solution in C++ FAQs to solve my problem in but I still don't know how to instantiate class template operators.

exterminator
January 18th, 2006, 12:47 AM
No multiple classes, but multiple operators.For that you will need to provide a template type parameter for the operator and not the class as a whole. Something like this:class MyOut
{
public:
template<typename T>
MyOut& operator<< (T t);
};

template<typename T>
MyOut& MyOut::operator<< (T t)
{
//your code
//return a non-local MyOut
}
...or if MyOut is to be a class template as well, then something like this:template<typename T>
class MyOut
{
public:
template<typename U>
MyOut<T>& operator<< (U u);
};

template<typename T>
template<typename U>
MyOut<T>& MyOut<T>::operator<< (U u)
{
//your code
//return a non-local MyOut
}I hope one of these is what you wanted or else you would need to elaborate a bit more on your problem. Regards.

Graham
January 18th, 2006, 04:29 AM
I'm struggling to figure out what you think you will achieve doing this. The only reason for having a template member is to write some generic code, and I don't see how an output operator can be generic. There's nothing to be gained by declaring a template and then explicitly specifying it for every type you can think of (apart from traits classes, but that's a different subject). You might as well just write overloads.

I, personally, find it useful to look at the way the standary library is structured if I'm contemplating doing something similar to some of its functionality. In this case, the standard's output streams don't define a template operator<<, they define specific overloads for the basic types and then leave the programmer to provide non-member implementations of operator<< for their own types. This is simple, extensible, and doesn't involve complex template techniques that some compilers (still) are not able to handle.

NMTop40
January 18th, 2006, 05:04 AM
I think the poster is asking how to specialise a template function.

That would be done like this:

class MyOut
{
public:
template < typename T > MyOut & operator<<( const T & );

// template specialisation for int.
template <> MyOut& operator<<( const int & i ); // or int i
};

The general case (not specialised) must be implemented in the header or you'll get linking errors. The specialised case can be implemented in MyOut.cpp.

Graham
January 18th, 2006, 06:39 AM
Oh, yeah, I see that. What I can't figure out is what he/she is expecting this code to do - what problem is it solving?

LSimao
January 18th, 2006, 10:33 AM
I'm getting I little frustrated!!!

Graham: I have actually implemented my function with inline operator, which solves linking problem. But inserting code in header files is not the correct way.
NMTop40: What you are talking about is specialization, not instantiation. I don't wan't to rewrite my code for each data type! I want my object/library file to contain template code for some kind of data types, just declaring them. That's instantiation. You cam see explicit intantiation in MSDN (http://msdn2.microsoft.com/en-us/library/by56e477(en-US,VS.80).aspx).

Now I'll try to show you my code and tell you what I want:

//report.h file:
class ReportOutput {
private:
iostream*file;
public:
template<typename T> ReportOutput& operator<<(T v);
};

//report.cpp file
template<typename T> ReportOutput& ReportOut::operator<<(T v) {
if (file) *file<<v;
cout<<v;
}
Using other modules to call operator<< will cause a linkage error because templates are not code, so report.obj will not contain any implementation of operator<< (see 250284).
So I need to force the compiler to create some code and put it in object file for some kind of types. That's instantiation. For generic functions we could do:

//Header file:
template<typename T> void f(T); //Generic declaration

template void f<int>(int); //Instantiation for int
template void f<double>(double); //Instantiation for double

//Code file:
template<typename T> void f(T t) {
//Do somethig with t...
}
That would work when called from other modules for int and double types, because object file will contain code for f(int) and f(double). I hadn't to rewrite code for each type, just declare the instantiation. But for member operators, I don't know how to instantiate them, or what is the syntax for doing that.

A even better solution would be using "export" keyword, has refered in 250284 but, as also refered there, my compiler does not support it!

Hope this can put this thread in the correct way!

Thanks you all!

exterminator
January 18th, 2006, 01:52 PM
Okay, I will take one last try, Is this what you are looking for?

#include<iostream>
#include<fstream>

class ReportOutput {
private:
std::fstream* file;
public:
template<typename T>
ReportOutput& operator<<(T t);

template<typename T>
friend void operator<<(std::ostream& os, T v);
};

template<typename T>
ReportOutput& ReportOutput::operator<<(T t){
if(file)
*file << t;
std::cout << t;
}

template<typename T>
void operator<<(std::ostream& os, T v) {
os << v;
}


template void operator<<(std::ostream& , int);
template ReportOutput& ReportOutput::operator<<(int t);
template ReportOutput& ReportOutput::operator<<(double t);

int main(){
//some code
return 0;
}
The operator<< must generally be a friend member as shown in my code above and the first argument should be osteam&. But, I have provided the codes for your wierd overloads. The code compiles fine on Comeau. VC++ 6.0 fails to do so and hence couldnt test the different file scenario but keeping the explicit instantiation part in an implementation file might work well. Hope this helps. Regards.

LSimao
January 18th, 2006, 02:31 PM
No, that's no solution. You are overloading, not instantiating. (And I have no problem with ostream, it was just an example.)
One can explicitaly instantiate functions and classes but not, or I don't know how, operators! If you don't really know what is instantiation, please see http://msdn2.microsoft.com/en-us/library/by56e477(en-US,VS.80).aspx and 250284.

While I was trying to test some code to show you my ideia, I get a "fatal error C1001: INTERNAL COMPILER ERROR", with VC++ 6.0. Maybe this compiler has several limitations on templates, like "extern". Maybe what I want is not possible...

On other words, I quit (at least by now)!

There are another solutions. Not so styliests. But working...

Thank you all, again!

googler
January 18th, 2006, 02:37 PM
Maybe I'm missing something, but I don't think you can define template operators. When you define a template function like this
template<class T> void f(T arg);
then the actual names of instantiations of the template are f<char>, f<int>, f<double> and so forth. If you defined a template operator like this:
template<class T> ostream& operator<<(ostream&, const T&);
then the actual names of instantiations of the template would be operator<<<int>, operator<<<char>, operator<<<double> and so forth. However, for a function name to be recognized as an overload of the left insertion operator, it must have the exact name operator<<, be it in global scope or member scope of some class. So an instantiation of this template would never be recognized as an overload of operator<<.

LSimao
January 18th, 2006, 02:44 PM
Googler!!! You get the point!!! Thanks!!!

I can define them, but I can't instantiate them (or again, I don't know how - and nobody told me that it is impossible)!

Actually I'm using inline template operators like this:

class ReportOut {
public:
template<typename T> Reportout& operator<<(T t) {
cout<<t;
}
};

and it is working. Without writing more code, just that piece, for all datatypes (well, not all, but to all supported by cout<<).

What I was trying to achieve in this thread is a way to change inline code to source file instead of header file and instantiate them...