I’m creating my own C++ tutorial, and I’m immersed in providing some template examples.
I know that the C++ Standard Library contains a Stack class, but I’m trying to provide relatively simple examples that don’t rely on using [much of] the C++ Standard Library.
I created a version of my own example template Stack class:
#ifndef TemplStack_h
#define TemplStack_h
template <typename TYPE>
class Stack
{
public:
Stack(size_t s)
: m_base(new TYPE[m_size = s])
{
m_top = m_base;
}
~Stack()
{
delete [] m_base;
}
void Push(const TYPE a)
{
*m_top++ = a;
}
TYPE Pop()
{
return *--m_top;
}
size_t Size() const
{
return m_top - m_base;
}
private:
TYPE* m_base; // The stack
TYPE* m_top; // The current top
size_t m_size; // The size of the stack
};
#endif /* TemplStack_h */
and tested it with this main program:
#include <iostream>
#include "TemplStack.h"
int main(int argc, const char * argv[])
{
const char* values[] = {"Mabel","George","Joe"};
Stack<const char *> mystack(100);
for (int i = 0; i < 3; i++)
{
mystack.Push(values[i]);
}
std::cout << "Size = "
<< mystack.Size() << std::endl
<< "Values: ";
for (int i = 0; i < 3; i++)
{
std::cout << mystack.Pop() << ' ';
}
std::cout << std::endl;
return 0;
}
It outputs the expected results.
So, then, I wanted to explore separating out the template class methods: declaration in the header file, definition in a separate .cpp file.
Here’s my new header file:
#ifndef TemplStack_h
#define TemplStack_h
template <typename TYPE>
class Stack
{
public:
Stack(size_t s);
~Stack();
void Push(const TYPE a);
TYPE Pop();
size_t Size() const;
private:
TYPE* m_base; // The stack
TYPE* m_top; // The current top
size_t m_size; // The size of the stack
};
#endif /* TemplStack_h */
and the corresponding .cpp file:
#include <iostream>
#include "TemplStack.h"
template <typename TYPE>
Stack<TYPE>::Stack(size_t s)
: m_base(new TYPE[m_size = s])
{
m_top = m_base;
}
template <typename TYPE>
Stack<TYPE>::~Stack()
{
delete [] m_base;
}
template <typename TYPE>
void Stack<TYPE>::Push(const TYPE a)
{
*m_top++ = a;
}
template <typename TYPE>
TYPE Stack<TYPE>::Pop()
{
return *--m_top;
}
template <typename TYPE>
size_t Stack<TYPE>::Size() const
{
return m_top - m_base;
}
The main program remained the same.
However, when I run this, I get several linker errors, and I’m very mystified by why they occur.
I’m using XCode on an iMac with compiler Apple Clang, GNU++20.
Here are the linker errors I’m getting:
ld: Undefined symbols:
Stack<char const*>::Pop(), referenced from:
_main in main.o
Stack<char const*>::Push(char const*), referenced from:
_main in main.o
Stack<char const*>::Stack(unsigned long), referenced from:
_main in main.o
Stack<char const*>::~Stack(), referenced from:
_main in main.o
_main in main.o
Stack<char const*>::Size() const, referenced from:
_main in main.o
It seems that the functions I defined in TemplStack.cpp aren’t being found.
I tried modifying the main program to:
#include <iostream>
#include "TemplStack.h"
int main(int argc, const char * argv[])
{
Stack<int> mystack(100);
/*
const char* values[] = {"Mabel","George","Joe"};
Stack<const char *> mystack(100);
for (int i = 0; i < 3; i++)
{
mystack.Push(values[i]);
}
std::cout << "Size = "
<< mystack.Size() << std::endl
<< "Values: ";
for (int i = 0; i < 3; i++)
{
std::cout << mystack.Pop() << ' ';
}
std::cout << std::endl;
*/
return 0;
}
That now produces the following link time errors:
ld: Undefined symbols:
Stack<int>::Stack(unsigned long), referenced from:
_main in main.o
Stack<int>::~Stack(), referenced from:
_main in main.o
which is even more mysterious, since my main program does not reference an unsigned long.
In case of a possible XCode configuration problem, I tried this in https://onecompiler.com/cpp/42v7wdnvw with the same results.
Any help would be appreciated. I’m interesting not only in solving the problem, but in particular why things are happening this way — I’m creating a tutorial, so it’s important for me to understand the why as well as the what.
Thanks!
You need to sign in to view this answers
Leave feedback about this