0

the interface of Stack.h

#include "stdafx.h"

//use linkedlist to implement the stack 
//which is different from using the array to implement the stack


#ifndef STACK_H
#define STACK_H

using namespace std;

namespace stackNameSpace {

template<class T>
struct StackNode {
    T value;
    T min_value; //current local min value 
    StackNode* next;
};

typedef StackNode<class T>* StackNodePtr;

template<class T>
class Stack {
private:
      StackNodePtr top;

public:

Stack();

Stack(const Stack& a_stack);

~Stack();

bool empty() const;

T pop();


void push(T the_value);

T getMin();

};

} //end of namespace

#endif

The implementation of the stack.h

#include "stdafx.h"

//use linkedlist to implement the stack 
//which is different from using the array to implement the stack


#ifndef STACK_CPP
#define STACK_CPP
#include <iostream>
#include <cstdlib>
#include "Stack.h"

using namespace std;

namespace stackNameSpace {


template<class T>
Stack<T>::Stack() : top(NULL)  //here should be Stack<T> instead of Stack
{}

template<class T>
Stack<T>::Stack(const Stack& a_stack) {
    if (a_stack.top == NULL) {
        return NULL;
    }
    else {
        StackNodePtr currentOld = a_stack.top;
        //construct the top of the new stack
        StackNodePtr currentNew = new StackNode<class T>;//the struct 
        currentNew->value = currentOld->value;
        currentNew->min_value = currentOld->min_value;
        top = currentNew;

        //contruct the rest node in the stack
        currentOld = currentOld->next;
        while (currentOld != NULL) {
            currentNew->next = new StackNode<class T>;
            currentNew = currentNew->next;
            currentNew->value = currentOld->value;
            currentNew->min_value = currentOld->min_value;

            currentOld = currentOld->next;
        }
        currentOld->next = NULL;

    }
}

template<class T>
Stack<T>::~Stack() {
    T data;
    while (!empty()) {
        data = pop();
    }
}

template<class T>
bool Stack<T>::empty() const {
    return (top == NULL);
}

template<class T>
T Stack<T>::pop() {

    if (empty()) {
        cout << "Error: popping an empty stack.\n";
        exit(1);
    }

    T result = top->value;

    StackNodePtr temp = new StackNode<class T>;
    temp = top;
    top = top->next;

    delete temp;

    return result;

}

template<class T>
void push(T the_value) {

    StackNodePtr temp = new StackNode<class T>;
    temp->value = the_value;

    temp->min_value = min(the_value, getMin());//This is Much better

    //temp->min_value = top->min_value; //This is NOT secure, since top may be NULL

    temp->next = top; //update the top node
    top = temp;

}

template<class T>
T getMin() {
    if (top == NULL) 
        return INT_MAX;
    else {
        return top->min_value;
    }
}

} //end of namespace 

#endif

The function using the Stack class

#include "stdafx.h"

#include <iostream>
#include "Stack.h" //this is not the <stack>, which is STL


//using namespace std; //NOTE: this must be wrong! because can not use multiple namespace at the same time
using namespace stackNameSpace;
using std::cout;
using std::endl;

int main() {

    Stack<int> sWithMin;

    sWithMin.push(5);
    cout<< sWithMin.getMin() << endl;
    sWithMin.push(4);
    cout<< sWithMin.getMin() << endl;
    sWithMin.push(5);
    cout<< sWithMin.getMin() << endl;
    sWithMin.push(3);
    cout<< sWithMin.getMin() << endl;
    sWithMin.push(6);
    cout<< sWithMin.getMin() << endl;



    return 0;

}

When I compile the project, I get an error in main() that "error C2079: 'stackNameSpace::StackNode::value' uses undefined class 'stackNameSpace::T'"

I can not figure out the reason why it has the error. Could anyone please help me?

  • possible duplicate of [Why can templates only be implemented in the header file?](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – Andy Prowl Apr 19 '13 at 21:23
  • This is not just the template not in header problem. – JoergB Apr 19 '13 at 21:56

2 Answers2

2
namespace stackNameSpace {

template<class T>
struct StackNode {
    T value;
    T min_value; //current local min value 
    StackNode* next;
};

So StackNode is a template that depends on a type parameter T.

typedef StackNode<class T>* StackNodePtr;

This is not part of a template definition and class T refers to a class named T.

(Actually class T always refers to a class named T, except in the construct template <class T>, which could be replaced by template <typename T>. With a template definition with type parameter T that type must be referred to using plain T, not class T.)

As you haven't declared a class named T yet, the StackNodePtr definition implicitly declares an incomplete class type at surrounding namespace scope (i.e the incomplete class type is ::stackNameSpace::T).

template<class T>
class Stack {
private:
      StackNodePtr top;

Now here StackNodePtr is not dependent on the template parameter T. Instead it is a pointer to a fixed type StackNode<::stackNameSpace::T> and top->value will be of incomplete type class T unrelated to the template parameter of Stack.

If you use a Stack<int> and instantiate anything using top->value within such a stack, you'll see the error you show.

BTW: another, unrelated issue is that definitions of templates (including member functions of class templates) must be visible at the point where a template is instantiated. Typically that means that you should not put template member definition into a cppfile which is compiled separately. Instead they should be in a header file that is included wherever the template is used.

JoergB
  • 4,383
  • 21
  • 19
1

While JoergB correctly pointed out the issue with the code that you posted, I would like to throw some light on what he was explaining in the last part of his answer.

When using templates in Visual studio I would make sure that the header and implementation of the class come under a single compilation unit. Try renaming Stack.cpp to Stack.inl and include it at the end of Stack.h

void push(T the_value);

T getMin();

};

} //end of namespace

#include "Stack.inl"

#endif

Be sure to exclude Stack.inl from build. Right click on it in the Solution Explorer > Properties > Exclude from build > Yes.

SNce
  • 2,453
  • 1
  • 16
  • 14