template compile errors

Discussion in 'C++' started by Thomi Richards, Oct 13, 2004.

  1. Hi,


    I'm trying to create a simple stack class using C++ and templates.
    Everything works well and good if I amke the class totally inline.
    However, as soon as I try to seperate the class into a .h and a .cpp
    file, gcc throws some strange linking errors.

    Compiling like this:

    gcc test.cpp stackList.cpp -lstdc++ -o test

    produces these errors:

    /tmp/ccCJLrbl.o(.text+0x84): In function `main':
    : undefined reference to `Stack<int>::Stack[in-charge]()'
    /tmp/ccCJLrbl.o(.text+0x101): In function `main':
    : undefined reference to `Stack<int>::push(int)'
    /tmp/ccCJLrbl.o(.text+0x10c): In function `main':
    : undefined reference to `Stack<int>::size() const'
    /tmp/ccCJLrbl.o(.text+0x18b): In function `main':
    : undefined reference to `Stack<int>::empty() const'
    /tmp/ccCJLrbl.o(.text+0x19c): In function `main':
    : undefined reference to `Stack<int>::size() const'
    /tmp/ccCJLrbl.o(.text+0x1aa): In function `main':
    : undefined reference to `Stack<int>::pop()'
    /tmp/ccCJLrbl.o(.text+0x20f): In function `main':
    : undefined reference to `Stack<int>::~Stack [in-charge]()'
    /tmp/ccCJLrbl.o(.text+0x229): In function `main':
    : undefined reference to `Stack<int>::~Stack [in-charge]()'
    collect2: ld returned 1 exit status


    I'm tearing my hair out... why would it not work in seperate files? My
    class definition is something like this:

    template <class T>
    class Stack
    {
    private:
    StackNode<T> *stackHead;
    /// The number of elements on the stack. It's easier to keep count
    /// of them here than to count them every time we need them.
    unsigned int stackSize;
    protected:
    public:
    /// Default constructor: set the stackSize to be 0.
    Stack(void);

    /// Default destructor: clean up any memory allocated.
    ~Stack(void);
    /// push: push an item onto the stack, and incrememt the size.
    bool push(T item);

    /// pop: return the topmost element from the stack, removing it
    from the stack at the same time:
    T pop(void);

    /// size: returns how many items are on the stack:
    unsigned int size(void) const;
    /// empty: return true if the stack is empty:
    bool empty(void) const;
    /// full: return true if the stack is full: - for a linked list
    implementation, this can be safely ignored:
    bool full(void) const;

    };


    and the code for a single method for the above class looks like this:

    template <class T> bool Stack<T>::push(T item)
    {
    if (full())
    return false;

    StackNode<T> *node = new StackNode<T> (item);
    node->Head = stackHead;
    stackHead = node;
    stackSize++;

    return true;
    }

    I've been following the C++ language tutorial, and a few books I own
    at home. It looks like I'm doing everything properly... Can anyone
    shed some light on this?


    Thanks,
    Thomi Richards, Oct 13, 2004
    #1
    1. Advertising

  2. Thomi Richards wrote:

    > Hi,
    >
    > I'm trying to create a simple stack class using C++ and templates.
    > Everything works well and good if I amke the class totally inline.
    > However, as soon as I try to seperate the class into a .h and a .cpp
    > file, gcc throws some strange linking errors.
    >
    > Compiling like this:
    >
    > gcc test.cpp stackList.cpp -lstdc++ -o test
    >
    > produces these errors:
    >
    > /tmp/ccCJLrbl.o(.text+0x84): In function `main':
    > : undefined reference to `Stack<int>::Stack[in-charge]()'
    > /tmp/ccCJLrbl.o(.text+0x101): In function `main':
    > : undefined reference to `Stack<int>::push(int)'
    > /tmp/ccCJLrbl.o(.text+0x10c): In function `main':
    > : undefined reference to `Stack<int>::size() const'
    > /tmp/ccCJLrbl.o(.text+0x18b): In function `main':
    > : undefined reference to `Stack<int>::empty() const'
    > /tmp/ccCJLrbl.o(.text+0x19c): In function `main':
    > : undefined reference to `Stack<int>::size() const'
    > /tmp/ccCJLrbl.o(.text+0x1aa): In function `main':
    > : undefined reference to `Stack<int>::pop()'
    > /tmp/ccCJLrbl.o(.text+0x20f): In function `main':
    > : undefined reference to `Stack<int>::~Stack [in-charge]()'
    > /tmp/ccCJLrbl.o(.text+0x229): In function `main':
    > : undefined reference to `Stack<int>::~Stack [in-charge]()'
    > collect2: ld returned 1 exit status
    >
    > I'm tearing my hair out... why would it not work in seperate files? My
    > class definition is something like this:
    >
    > template <class T>
    > class Stack
    > {
    > private:
    > StackNode<T> *stackHead;
    > /// The number of elements on the stack. It's easier to keep count
    > /// of them here than to count them every time we need them.
    > unsigned int stackSize;
    > protected:
    > public:
    > /// Default constructor: set the stackSize to be 0.
    > Stack(void);
    >
    > /// Default destructor: clean up any memory allocated.
    > ~Stack(void);
    > /// push: push an item onto the stack, and incrememt the size.
    > bool push(T item);
    >
    > /// pop: return the topmost element from the stack, removing it
    > from the stack at the same time:
    > T pop(void);
    >
    > /// size: returns how many items are on the stack:
    > unsigned int size(void) const;
    > /// empty: return true if the stack is empty:
    > bool empty(void) const;
    > /// full: return true if the stack is full: - for a linked list
    > implementation, this can be safely ignored:
    > bool full(void) const;
    >
    > };
    >
    > and the code for a single method for the above class looks like this:
    >
    > template <class T> bool Stack<T>::push(T item)
    > {
    > if (full())
    > return false;
    >
    > StackNode<T> *node = new StackNode<T> (item);
    > node->Head = stackHead;
    > stackHead = node;
    > stackSize++;
    >
    > return true;
    > }
    >
    > I've been following the C++ language tutorial, and a few books I own
    > at home. It looks like I'm doing everything properly... Can anyone
    > shed some light on this?
    >
    > Thanks,


    code for a template doesn't really exist until you instantiate it... in
    a very raw sense they are kind of like
    macros in that regard. Until you use them, no code or data gets
    generated. If you just take part of a group of template definitions and
    stick them in a C++ file, no code will be generated in the file, and you
    end up with essentially the same problem as if you are working in C and
    move all the global #defines into a C language source file, they just
    wouldn't be accessible. What happens when you instantiate a template is,
    the compiler takes all the structures and functions you have declared
    related to the template and tries to make functions out of them, using the
    instantiated types instead of the placeholder types you used when you
    declared the template. So you can instantiate one template using many
    many different types in the course of a single program, but the cost is
    that each time you change the types given in the instantiation, the
    compiler generates another set of code and data specific to those types.

    You might be able to fix this particular problem by instantiating a
    template using the <int> type in your source file that you put the
    templates in, that may at least cause the functions to get declared so
    they will appear at link time. However, that means that for every time
    you want to use that template with a different type, you've got to go into
    your source file and instantiate it deliberately. Since that really cuts
    down on the power of templates dramatically, it is usually recommended you
    just group all the template functions and so forth in header files, but of
    course that is its own problem since if you are modifying global headers
    very often it can force you to recompile large parts of your project on a
    regular basis.

    David
    David Lindauer, Oct 13, 2004
    #2
    1. Advertising

  3. Thomi Richards wrote:

    > I'm trying to create a simple stack class using C++ and templates.
    > Everything works well and good if I amke the class totally inline.
    > However, as soon as I try to seperate the class into a .h and a .cpp
    > file, gcc throws some strange linking errors.
    >
    > Compiling like this:
    >
    > gcc test.cpp stackList.cpp -lstdc++ -o test
    >
    > produces these errors:
    >
    > /tmp/ccCJLrbl.o(.text+0x84): In function `main':
    > : undefined reference to `Stack<int>::Stack[in-charge]()'
    > /tmp/ccCJLrbl.o(.text+0x101): In function `main':
    > : undefined reference to `Stack<int>::push(int)'
    > /tmp/ccCJLrbl.o(.text+0x10c): In function `main':
    > : undefined reference to `Stack<int>::size() const'
    > /tmp/ccCJLrbl.o(.text+0x18b): In function `main':
    > : undefined reference to `Stack<int>::empty() const'
    > /tmp/ccCJLrbl.o(.text+0x19c): In function `main':
    > : undefined reference to `Stack<int>::size() const'
    > /tmp/ccCJLrbl.o(.text+0x1aa): In function `main':
    > : undefined reference to `Stack<int>::pop()'
    > /tmp/ccCJLrbl.o(.text+0x20f): In function `main':
    > : undefined reference to `Stack<int>::~Stack [in-charge]()'
    > /tmp/ccCJLrbl.o(.text+0x229): In function `main':
    > : undefined reference to `Stack<int>::~Stack [in-charge]()'
    > collect2: ld returned 1 exit status
    >
    >
    > I'm tearing my hair out... why would it not work in seperate files?
    > My class definition is something like this:
    >
    > template <class T>
    > class Stack
    > {
    > private:
    > StackNode<T> *stackHead;
    > /// The number of elements on the stack. It's easier to keep count
    > /// of them here than to count them every time we need them.
    > unsigned int stackSize;
    > protected:
    > public:
    > /// Default constructor: set the stackSize to be 0.
    > Stack(void);
    >
    > /// Default destructor: clean up any memory allocated.
    > ~Stack(void);
    > /// push: push an item onto the stack, and incrememt the size.
    > bool push(T item);
    >
    > /// pop: return the topmost element from the stack, removing it
    > from the stack at the same time:
    > T pop(void);
    >
    > /// size: returns how many items are on the stack:
    > unsigned int size(void) const;
    > /// empty: return true if the stack is empty:
    > bool empty(void) const;
    > /// full: return true if the stack is full: - for a linked list
    > implementation, this can be safely ignored:
    > bool full(void) const;
    >
    > };
    >
    >
    > and the code for a single method for the above class looks like this:
    >
    > template <class T> bool Stack<T>::push(T item)
    > {
    > if (full())
    > return false;
    >
    > StackNode<T> *node = new StackNode<T> (item);
    > node->Head = stackHead;
    > stackHead = node;
    > stackSize++;
    >
    > return true;
    > }


    Since you didn't tell us, I'll suppose that
    you moved the function template definitions
    from your stackList.h header file
    to your stackList.cpp source file and that
    you include'd the stackList.h header file
    but *not* the stackList.cpp source file
    in your test.cpp source file.

    Please allow me to ask a simple question,

    "How does the C++ compiler know
    where to find the function template definitions
    so that it can instantiate them
    when it is compiling test.cpp?"

    > I've been following the C++ language tutorial,
    > and a few books I own at home.


    > info gcc 'C++ extensions' 'Template Instantiation'


    > It looks like I'm doing everything properly...
    > Can anyone shed some light on this?


    If you know all of the template functions that you need.
    you can instantiate the template functions *explicitly*:

    template Stack<int>::Stack(void);
    template std::bool Stack<int>::push(int);
    template size_t Stack<int>::size(void) const;
    template std::bool Stack<int>::empty(void) const;
    template int Stack<int>::pop(void);
    template void Stack<int>::~Stack(void);

    right after the function template definitions
    in your stackList.cpp source file.
    E. Robert Tisdale, Oct 13, 2004
    #3
  4. Thomi Richards

    David Hilsee Guest

    "Thomi Richards" <> wrote in message
    news:...
    > Hi,
    >
    >
    > I'm trying to create a simple stack class using C++ and templates.
    > Everything works well and good if I amke the class totally inline.
    > However, as soon as I try to seperate the class into a .h and a .cpp
    > file, gcc throws some strange linking errors.
    > [...]
    > I'm tearing my hair out... why would it not work in seperate files? My
    > class definition is something like this:
    > [...]


    See the FAQ (http://www.parashift.com/c -faq-lite/), section 34 ("Container
    classes and templates"), question 12 ("Why can't I separate the definition
    of my templates class from it's declaration and put it inside a .cpp file?")
    and the related questions that follow.

    --
    David Hilsee
    David Hilsee, Oct 13, 2004
    #4
  5. Ahh,

    Thanks for that.
    Thomi Richards, Oct 13, 2004
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mark Goldin

    Errors, errors, errors

    Mark Goldin, Jan 17, 2004, in forum: ASP .Net
    Replies:
    2
    Views:
    912
    Mark Goldin
    Jan 17, 2004
  2. Fernando Cuenca
    Replies:
    4
    Views:
    2,508
    Gianni Mariani
    Sep 6, 2004
  3. Nagaraj
    Replies:
    1
    Views:
    823
    Lionel B
    Mar 1, 2007
  4. aaragon
    Replies:
    6
    Views:
    1,168
    aaragon
    Mar 23, 2008
  5. kurt krueckeberg
    Replies:
    1
    Views:
    306
    Victor Bazarov
    Apr 29, 2013
Loading...

Share This Page