0

I have to implement a template class called Stack for a class assignment. Stack has an overloaded stream insertion operator. Here is a related excerpt from the Stack.h file:

...
#include <iostream>
using namespace std;

template<class T>
ostream& operator<<(ostream&,Stack<T>&);

template<class T>
class Stack
{
    public:
        friend ostream& operator<< <T>(ostream&,Stack<T>&);
        ...             
};

#include "Stack.cpp"
...

I cannot change Stack.h since it was given as is. the related excerpt from Stack.cpp is:

template <class T>
ostream& operator<< (ostream& out, Stack<T>& stack)
{
    Stack<T>::Node* current = stack.top;

    out << "[";

    while (current)
    {
        out << current->element;
        current = current->next;
        if (current)
            out << ",";
    }

    out << "]";

    return out;
}
...

This compiles and works fine in Visual Studio, however, when compiled with g++, it gives the following errors:

Stack.cpp:4: syntax error before '&'
Stack.cpp:4: 'ostream' was not declared in this scope
Stack.cpp:4: 'out' was not declare din this scope
Stack.cpp:4: 'Stack' was not declared in this scope
Stack.cpp:4: 'T' was not declared in this scope
Stack.cpp:4: 'stack' was not declared in this scope
Stack.cpp:5: declaration of 'operator <<' as non-function

why is this? What can be done to fix it?

EDIT: I added that I have already included iostream and provided the namespace.

Gerome Schutte
  • 184
  • 1
  • 11

3 Answers3

2

You cannot refer to the undeclared Stack<T> in the operator<< declaration. You need a forward declaration template<class T> Stack; either at the top of Stack.h, or before the inclusion of Stack.h in every file that includes it.

Casey
  • 41,449
  • 7
  • 95
  • 125
2

You should ask your professor for permission to make several changes to the header file, like this:

#include <iostream>
//using namespace std; is a VERY bad idea in header files, since it infects the entire program

template<class T>
class Stack; // Casey's fix

// need to qualify ostream since using namespace std; went away
template<class T>
std::ostream& operator<<(std::ostream&,Stack<T>&);

template<class T>
class Stack
{
    public:
        friend std::ostream& operator<< <T>(std::ostream&,Stack<T>&);
        ...             
};

// The .cpp extension by convention is used only for source files, not for inclusion targets.
// Pick a different extension for template implementations, which get passed to #include
#include "Stack.impl"

If your professor doesn't see the value of these changes, staying in his class will be quite negative due to all the bad habits you will pick up, you should start thinking about other options for learning C++.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
0

The problem was that I tried to compile Stack.cpp separately. The solution was, only compiling the file that uses the template class, in this case, main.cpp

My erroneous makefile would have looked as follows:

main: main.o Stack.o
    g++ -static main.o Stack.o -o main

main.o: main.cpp
    g++ -c main.cpp

Stack.o: Stack.cpp Stack.h
    g++ -c Stack.cpp

the correct makefile is

main: main.o
    g++ -static main.o -o main

main.o: main.cpp Stack.cpp Stack.h
    g++ -c main.cpp

thanks to juanchopanza for pointing this out.

Gerome Schutte
  • 184
  • 1
  • 11
  • The rule for `Stack.o: Stack.cpp` is actually predefined in the make system using a pattern. This is why one should not name header files `.cpp`. – Ben Voigt Feb 08 '14 at 16:10