1

Before you mark this question as a duplicate, please realize that I did have a look at this post and other similar ones on the site. My issue is not with understanding how variable scopes and/or the preprocessor work. I've got those down.

I can't figure out this pesky problem in my code. I'm just trying to model a stack data structure using C++. The compiler keeps complaining that size and capacity were not declared in this scope (for Stack.cpp). There are three files:

  • Stack.h
  • Stack.cpp
  • Main.cpp

Below are the code snippets for the header file and the .cpp file:

Stack.h

#ifndef STACK_H_
#define STACK_H_


#include <iostream>
#include <string>


using namespace std;


template<typename T> 
class Stack
{   
    public:
        Stack();
        void push(T item);
        T pop();

    private:
        int size;
        const int capacity = 10;
        T items[];  
};


#endif

Stack.cpp

#include "Stack.h"

using namespace std;

template<typename T>
Stack::Stack() : items[capacity]
{
    size = 0;
}


template<typename T>
void Stack::push(T item)
{
    if(size == capacity)
    {
        cout << "No more room left. Unable to add items.";
    }   
    else
    {
        items[size-1] = item;
        size++;
    }
}


template<typename T>
T Stack::pop()
{
    if(size == 0)
    {
        cout << "Stack is empty. There is nothing to remove.";
    }
    else
    {
        size--; 
    }
}

The compiler also strangely complains that "'template class Stack' used without template parameters void Stack::push(T item)", which doesn't make much sense, seeing as how I did use the template header before the member function.

Could someone please clarify what I did wrong?

Community
  • 1
  • 1
  • 1
    http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file will steer you in a better direction. Also the templated typename is Stack. – Captain Giraffe Feb 16 '17 at 22:50

2 Answers2

2

I went through your problem, fixed few problems and optimized (just a recommendation), so:

  1. First problem was that you templated the whole class not just separate functions, others answered before. So you need to use template list with each function except constructor.
  2. Second problem occurs when you fix the first one, compiler wont compile the code, because you use separate files for definition and implementation (you cannot do that with templated classes - atleast not in the usual way Explanation).
  3. Third and the last problem occurs in the pop functions, as it is defined in such manner, that it must return something and in the body you do not return anything (my change is just temporary fix).
  4. Fixed size changing in push.

Now the optimizations:

  1. Removed using namespace std. Explanation
  2. Changed capacity that it is user settable (at least at stack instantiation time).
  3. Changed items array to std::unique_ptr smart pointer pointing to dynamically created array.
  4. Added member initializer list to constructor.

Code (Stack.h):

#ifndef STACK_H_
#define STACK_H_

#include <iostream>
#include <memory> // for unique_ptr

//using namespace std; // it is better to not use using namespace, for avoiding of problems in the future

template<typename T>
class Stack {
public:
    Stack(const unsigned int& capacity = 10); // usually stacks are defined with user settable capacity
    void push(T item);
    T pop();
private:
    unsigned int size;
    unsigned int capacity;
    std::unique_ptr<T[]> items;
};

// such templated functions (below) cannot be implemented in other file

template<typename T>
Stack<T>::Stack(const unsigned int& capacity) :
    capacity(capacity),
    items(new T[capacity]),
    size(0) {}

template<typename T>
void Stack<T>::push(T item) {
    if (size == capacity) {
        std::cout << "No more room left. Unable to add items." << std::endl;
    }
    else {
        items[size++] = item; // you should put item at index size, after that increase it by one
    }
}

template<typename T>
T Stack<T>::pop() {
    // for such defined function you need to return something of type T
    if (size == 0) {
        std::cout << "Stack is empty. There is nothing to remove." << std::endl;
        return 0; // maybe return empty object?
    }
    else {
        return items[--size]; // probably return removed object
    }
}

#endif

Code (main.cpp):

#include "Stack.h"

int main() {
    Stack<int> stack;
    for (int e = 0; e < 11; e++) {
        stack.push(e);
    }
    for (int i = 0; i < 11; i++) {
        std::cout << stack.pop() << std::endl;
    }
    return 0;
}

Hope this helps.

Community
  • 1
  • 1
0

The compiler also strangely complains that "'template class Stack' used without template parameters void Stack::push(T item)"

I think the compiler is trying to tell you that in the cpp file you used Stack where you should have used Stack<T>. For example, your push declaration should look like this...

 template<typename T>
 void Stack<T>::push(T item)
 // ... etc ...
Frank Boyne
  • 4,400
  • 23
  • 30