C++ Templates and a Linker Error - c++

Please consider the following C++ program:
#include <iostream>
using namespace std;
template <class T> class Array
{
T *pType;
int itsSize;
public:
// template <class T>
friend ostream &operator<< (ostream &, Array<T> & );
};
template <class T>
ostream &operator<< (ostream &output, Array<T> &theArray)
{
return (output);
}
ostream &operator<< (ostream &, Array<int> &);
int main ()
{
Array<int> theArray;
cout << theArray << endl;
return 0;
}
The above code compiles but the linker gives the following error:
undefined symbol `operator<<(std::ostream&, Array&)'
I believe I need to tell the compiler to instantiate a function for the operator << but I do not know how to do that.
Bob

No, you don't need to tell the compiler to instantiate a template, it does that all by itself, if and when needed.
Your line
ostream &operator<< (ostream &, Array<int> &);
actually tells the compiler that you have some other operator for Array<int> so that it shouldn't use the template for that type.
So the linker goes looking for this other operator, but of course doesn't find any.
If you just remove that extra declaration, it should work much better.

The declaration
ostream &operator<< (ostream &, Array<int> &);
is not telling the compiler to instantiate the template. It is declaring a separate and distinct non-templated function i.e. overloading.
Within main(), the usage of operator<<() resolves to the declared function. The compiler does not need to specialize the template to find a match. However, since there is no definition (i.e. implementation) of that function, the linking fails.
Remove that declaration and you should find that your code compiles and links.
Incidentally, output streaming operators generally don't change the object being output. It is therefore advisable to change the templated ostream &operator<< (ostream &, Array<T> & ) to be ostream &operator<< (ostream &, const Array<T> & )
Also, since templates (typically) need to be defined in header files, and header files are included in multiple source files, it is better to avoid using namespace std, and replace ostream with std::ostream.

There are issues with your code, #BoPersson and #Perter pointed out some.
But even if you change what they suggested (Here is a live demo on ideone) and I ran it on my VS 2015 too. The compilers are still mad.
Ideone says:
prog.cpp:10:55: warning: friend declaration 'std::ostream& operator&)' declares a non-template function [-Wnon-template-friend]
friend ostream &operator & );
^
prog.cpp:10:55: note: (if this is not what you intended, make sure the function template has already been declared and add after the function name here)
/home/FHMhT9/ccNwcxP0.o: In function `main':
prog.cpp:(.text.startup+0x1b): undefined reference to `operator&)'
collect2: error: ld returned 1 exit status
And VS gives the pretty much same errors too.
Ideone is telling me, that the friend declaration in the class declares a non-template function.
So, change the declaration in the class to:
friend ostream &operator<< <T> (ostream &, Array<T> & );
// ^^^^^
// I added this <T> to tell the compiler that it is a template function.
But you need to define the function before this, so cut the implementation of operator<< and then paste it before the class. But you'd need a forward declaration of the class for that to work. So finally your code becomes pretty much like this:
And I changed the Array<T> & to const Array<T> & too.
#include <iostream>
template <typename T>
class Array;
template <class T>
std::ostream &operator<< (std::ostream &output, const Array<T> &theArray)
{
output << "abc";
return (output);
}
template <class T> class Array
{
T *pType;
int itsSize;
public:
// template <class T>
friend std::ostream &operator<< <T> (std::ostream &, const Array<T> &);
};
int main()
{
Array<int> theArray;
std::cout << theArray << std::endl;
return 0;
}
and this version now works.

Related

How do I define an overloaded operator outside of a class template? [duplicate]

This question already has answers here:
overloading friend operator<< for template class
(5 answers)
Closed 2 years ago.
I want to overload the << operator in my template class, and define it outside the template class.
using namespace std;
template <class T> class Child {
public:
friend ostream &operator << (ostream &Output, const Child &Object);
};
// What can I change to make my code work?
ostream &operator << (ostream &Output, const Child <T> &Object) {
}
As you can see, I don't know what the correct syntax is so that my code can run without errors. My C++ book does not go this in-depth. This has been really frustrating me so I would appreciate any help. Thank you :)
It needs to be a function template if you're going to have it accept a templated type (const Child<T> &Object). So try:
template <class T>
std::ostream &operator << (std::ostream &Output, const Child<T> &Object)
{ ... }
That should get you farther along.
The cleanest way is:
template <class T>
class Child {
void print(std::ostream& os)const;
public:
friend std::ostream &operator << (std::ostream &Output, const Child &Object){
Object.print(Output);
return Output;
}
};
// implement Child<T>::print here
a minimal amout of "glue" inline in the friend operator, forwarding to a conventional method with the meat in it.
This makes the syntax obvious to readers, and I find non-template friends of templates to be more sane than the other alternatives (like template friends to template types).
Firstly, since class templates typically need to be defined in a header (in order to use them effectively from multiple source files) remove the using namespace std and refer to ostream as std::ostream. A quick search will find numerous explanations of why using directives (like using namespace std) are best avoided in header files.
This means changing the class definition to
template <class T> class Child
{
public:
friend std::ostream &operator << (std::ostream &Output, const Child &Object);
};
The definition of the function (outside the class definition) may then be changed to
template<class T> std::ostream &operator << (std::ostream &Output, const Child <T> &Object)
{
// presumably operations that stream members of Object to Output in some way
return Output;
}

C++ friend template function - minGW error but not VS2015

The following code compiles without a problem with Visual Studio 2015 but with minGW gets the warning and error shown below it:
#include <iostream>
using std::ostream;
template<typename ElemType, int SIZE>
class Array
{
friend ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value);
ElemType operator[](int index) const;
private:
ElemType elements[SIZE];
};
template<typename ElemType, int SIZE>
ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value);
template<typename ElemType, int SIZE>
ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value)
{
out << elements[0];
return out;
}
mingw32-g++.exe -Wall -g -pedantic-errors -pedantic -Wextra -Wall -std=c++98 -c Test.cpp
Test.cpp:7:79: warning: friend declaration 'std::ostream& operator<<(std::ostream&, const Array<ElemType, SIZE>&)' declares a non-template function [-Wnon-template-friend]
Test.cpp:7:79: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
Test.cpp: In function 'std::ostream& operator<<(std::ostream&, const Array<ElemType, SIZE>&)':
Test.cpp:21:11: error: 'elements' was not declared in this scope
I'm far from an expert on some of this stuff so I'm not sure what the issue is. It seems like it's telling me it needs the follwoing code just before the friend declaration in the class itself, but when I put it there it causes other compilation errors:
template<typename ElemType, int SIZE>
Thanks in advance!
After making the changes suggested by #Trevor Hickey in his post below the warning about the friend template function went away. However, I still get the error about "elements" (in the friend function) not being declared in scope.
There's two separate problems in your code. The easier one is that out << elements[0]; should be out << value.elements[0];. This is because you want to print the element that is a member of the parameter value. Remember that we are in a non-member function here, there is no this and no members you can access by unqualified name.
The other one is known as the template friends problem. So far you only get a warning, but if you try to compile a complete program you get an error. I added the code:
int main() { Array<int, 5> a; std::cout << a; }
and the error appears:
undefined reference to `std::ostream& operator<< <int, 5>(std::ostream&, Array<int, 5> const&)'
The problem is that your code:
friend ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value);
actually declares that there is a non-template function which will be the friend to this instance of Array. Later, when you write cout << a in main, the compiler matches that << to this non-template declaration. It never gets so far as the body for operator<< that you provided later, and so never instantiates a copy of that body, hence the undefined reference error.
One way to fix this is to explicitly instantiate the body. But this is lame as you'd have to write an explicit instantiation for each possible instantiateion of Array that occurs for your code. So we won't do this.
The simplest solution is to put the body of operator<< inline in the class definition.
The other option is to declare that operator<< is a template function.
Trevor Hickey's code shows one way of doing this, although that has a drawback that Array<A, B>::elements can be accessed by Array<C, D>::operator<<.
A more secure way is to declare the operator<< before the class:
template<typename ElemType, int SIZE>
class Array;
template<typename ElemType, int SIZE>
ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value);
and then the rest of your code as it was before. Now, the friend declaration in the class will match the pre-existing template, instead of declaring a new non-template.
You are using the template paramters from the class, but the function itself is not a template function. It needs to be a template function as seen in the definition.
#include <iostream>
using std::ostream;
template<typename ElemType, int SIZE>
class Array
{
template<typename T, int U>
friend ostream &operator<<(ostream &out, const Array<T, U> &value);
ElemType operator[](int index) const;
private:
ElemType elements[SIZE];
};
template<typename ElemType, int SIZE>
ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value)
{
out << value.elements[0];
return out;
}

ostream must take exactly one argument

I am getting a compile error in my output stream operator and I cannot seem to find out how to fix it as I never received this error before:
linkedList.cpp:258: error: ‘std::ostream& linkedList<T>::operator<<(std::ostream&, linkedList<T>)’ must take exactly one argument
make: *** [linkedList.o] Error 1
Here is the definition of my operator<<
template <class T>
ostream& linkedList<T>::operator<<(ostream &output, linkedList<T> list)
{
node *curr;
curr=list.head;
while(curr!=NULL )
{
output << curr->data;
curr = curr->next;
}
return output;
}
Here it is in my header:
//ostream operator for printing the list
template <class T>
ostream &operator<<(ostream &output, linkedList<T> list);
Any help will be appreciated!
You defined it as a member function, you have to define it as a free standing (probably friend) function, either
outside your class
template <class U>
ostream& operator<<(ostream &output, linkedList<U> list){...}
in which case you also have to declare it inside the class as
template <class U> // note the different type name
friend ostream& operator<<(ostream &output, linkedList<U> list)
or
inside the class as
// no need for template, type is passed automatically the function is not templated anymore
friend ostream& operator<<(ostream &output, linkedList list){...}
The difference between these 2 declarations is a bit subtle, but for your purpose both work equally well. And probably you want to pass linkedList by const reference, linkedList<T>& list.
EDIT
A common mistake is to just declare the friend operator inside the class as
template<typename T>
class linkedlist
{
//....
friend ostream& operator<<(ostream& output, const linkList& list); // declaration only
}
then try to define it outside the class as
template<typename T>
ostream& operator<<(ostream& output, const linkList<T>& list){...}
Guess what? The code will compile, but won't link, as the declaration inside the class declares a non-template function, one for each type T you pass to linkList<T>. Then, when you declare e.g. linkList<int> lst, and try cout << lst, the compiler will see the declaration of the friend, which for it looks like
friend ostream& operator<<(ostream& output, const linkList<int>& list);
and will try searching for its definition. However there is no definition in the rest of the header, only the template operator, so the linker isn't able to find the implementation and will spit a linker error. Live example here.
It's all in the error message. This function that you declared:
template <class T>
ostream &operator<<(ostream &output, linkedList<T> list);
is a member function of linkedList<T> that takes two arguments. All the binary operators (+, *, <<, ... all except for the call operator ()), when defined as member functions, must take exactly one argument, hence the error. What you had intended to do was to declare a non-member function, external to the class:
template <typename T>
class linkedList { .. };
template <typename T>
ostream &operator<<(ostream &output, linkedList<T> list) {
// implementation
}
You could also define it as a non-member friend inside the class definition:
template <class T>
class linkedList {
...
friend ostream &operator<<(ostream &output, linkedList list){
...
}
...
};

template class and insertion extraction overloaded

How can I make the insertion (<<) and/or extraction (>>) operator overloaded in a template class WITHOUT making it inline. I would like to have the << or >> operator as a friend class.
I know how to make it inline
example of inline in a matrix class
friend ostream& operator<<(ostream& ostr, const Matrix<T>& inputMatrix)
{
...
// create the ostr
return ostr;
}
but I'd like to have the code outside of the templateclass definition.
g++ told me to add <> after the function name so I did but when I tried to instansiate a matrix of type SOMETYPE it gave me an error that it didn't know how to extract or insert for that type.
If you really want to define the operator externally and befriend only the operator instantiation that coincides in type with this template instantiation, the correct syntax is:
template <typename T> class test; // forward declare template class
template <typename T> // forward declare the templated operator
std::ostream& operator<<( std::ostream&, test<T> const & );
template <typename T>
class test { // define the template
friend std::ostream& operator<< <T>( std::ostream&, test<T> const & ); // befriend
};
template <typename T> // define the operator
std::ostream& operator<<( std::ostream& o, test<T> const & ) {
return o;
}
In most cases it is not worth the hassle to pull the definition out of the class, considering that you still need to provide it in a header and the extra work required.
Also note that there are slight differences for the compiler regarding lookup. In the case where the function is inlined inside the class definition, the compiler will not find that function unless one of the arguments is actually of the type of the template, so it effectively reduces the visibility and the amount of work that the compiler has to do (if the templated operator<< is defined outside of the class, the compiler will find it as a candidate for overload resolution in all places where it finds a << b, only to discard it in all cases where the second argument is not a test<T> (and it will show the templated operator as a candidate in all error messages where it cannot match operator<<, which is a long enough list already).
Try something like:
template <typename T> class Matrix;
template <typename T> std::ostream& operator<<(std::ostream& ostr, const Matrix<T>& m);
template <Typename T>
class Matrix
{
public:
friend ostream& operator<< <T> (ostream& ostr, const Matrix<K>& inputMatrix);
};
// This must be in the same translation unit as the class definition!
template<typename T>
ostream& operator<<(ostream& ostr, const Matrix<T>& inputMatrix)
{
// ...
return ostr;
}
Translation unit reference
re-re-edited to addressed the comments made by aschepler and dribeas.
Place the code in the header, outside the class definition. Or, place it in a .tcc file and include it at the bottom of the header.

signature output operator overload

do you know, how to write signature of a function or method for operator<< for template class in C++? I want something like:
template <class A> class MyClass{
public:
friend ostream & operator<<(ostream & os, MyClass<A> mc);
}
ostream & operator<<(ostream & os, MyClass<A> mc){
// some code
return os;
}
But this just won't compile. Do anyone know, how to write it correctly?
All the below said, if you don't need an operator to be a friend, then don't make it a friend. For output operators in particular, in my opinion you should not make them friends. That is because if your class can be output to a stream, it should have equivalent get functions that provide the same data programmatically. And in that event, you can write a operator<< as a non-friend in terms of those get functions.
In case you have some good reason for making them friends, you can do a friend definition
template <class A> class MyClass {
public:
friend ostream & operator<<(ostream & os, MyClass<A> const& mc) {
// ...
}
};
That way you don't need the template<...> clause that gets you the type A. It's alreay known if you define the operator inside the template. Note that even though you defined it inside the template, it's not a member function. It's still a non-member, but has access to the names declared in the class (like the template parameter). For each instance of MyClass you create, a different non-template operator function is created out of that friend function that prints things.
If you want to define the template outside, you have to predeclare it to be able to declare a given specialization of it as a friend.
// predeclare it so you can make it a friend.
template <class A> class MyClass;
template <class A> ostream &operator<<(ostream &os, MyClass<A> const&);
template <class A> class MyClass{
public:
/* the "<A>" is needed - it says that a given instantiation of
that template is a friend, and not a non-template function. */
friend ostream & operator<< <A>(ostream & os, MyClass<A> const& mc);
};
template <class A>
ostream & operator<<(ostream & os, MyClass<A> const& mc){
// some code
return os;
}
That makes operator<< <Foo> a friend of MyClass<Foo>. If you were to omit the <A> or an also possible empty <>, the compiler would understand that as saying you made a non-template operator having concrete instead of templated parameters as friend.
The more easy but less "correct" solution is to make MyClass <Foo> have as friend all the operator << instantiations. So theoretically operator << <Bar> could access private members of MyClass <Foo>. It's not what is wanted, but it works too, gaining more access than needed. It gets rid of the need for forward declaring:
template <class A> class MyClass{
public:
/* make all instantiations friends. */
template<typename T>
friend ostream & operator<<(ostream & os, MyClass<T> const& mc);
};
template <class T>
ostream & operator<<(ostream & os, MyClass<T> const& mc){
// some code
return os;
}