C++ template class linking issue

Discussion in 'Mac Programming' started by GeeYouEye, Feb 13, 2006.

  1. macrumors 68000

    GeeYouEye

    Joined:
    Dec 9, 2001
    Location:
    State of Denial
    #1
    Hopefully someone can figure out what's going on... I sure can't...

    in main.cpp:
    Code:
    #include <iostream>
    #include <fstream>
    #include <string>
    #include "symtab.h"
    #include "OpCode.h"
    using namespace std;
    int main(int argc, char **argv)
    {
    ...
    }
    
    in OpCode.h:
    Code:
    #ifndef OPCODE_H
    #define OPCODE_H
    #include <string>
    
    using namespace std;
    class OpCode
    {
    public: 
    	OpCode(string mnem);
    	OpCode(string mnem, char hex, int bytes, string otherInfo);
    	string getMnem() { return iMnem;}
    	char getHex() {return iHex;}
    	int getBytes() {return length;}
    	string getOtherInfo() {return info;}
    private:
    	string iMnem;
    	char iHex;
    	int length;
    	string info;
    };
    #endif
    in OpCode.cpp
    Code:
    OpCode::OpCode(string mnem){iMnem = mnem;}
    OpCode::OpCode(string mnem, char hex, int bytes, string otherInfo)
    {
    	iMnem = mnem;
    	iHex = hex;
    	length = bytes;
    	info = otherInfo;
    }
    
    Note that all the other functions in OpCode are defined inline.

    in symtab.h (where I suspect I'm missing something):
    Code:
    #ifndef SYMTAB_H
    #define SYMTAB_H
    
    #include <string>
    using namespace std;
    template <class AT>
    class Item {
        public:
            Item(string s);
            string getname(); // returns the name
            AT attr; // attributes other than name
        private:
            string name;
        };
    
    template <class AT>
    struct Node{
        Item<AT> * info;
        Node<AT> * link;};
    
    template <class AT>
    class SymTab {
        public:
            SymTab(); //initializes to the empty table
            Item<AT> * find(string s); //returns Item pointer or null
            Item<AT> * insert(string s); //inserts if necessary and 
                                         //returns Item pointer
            ~SymTab(); //This seems almost more necessary than the constructor
    
        private:
            Node<AT> hashTab[137]; 
            int hash(string s);
            Node<AT> * cons(Item<AT> * x, Node<AT> * y); //returns a new list node
                               // with x in the info field and y in the link field
        };
    
    #endif
    and in symtab.cpp
    Code:
    #include "symtab.h"
    template <class AT>
    Item<AT>::Item(string s)
    {
        name = s;
    }
    template <class AT>
    string Item<AT>::getname() { return name;} // returns the name
    
    template <class AT>
    SymTab<AT>::SymTab()
    {
    }
    
    template <class AT>
    Item<AT> * SymTab<AT>::find(string s)
    {
    ...
    }
    
    template <class AT>
    Item<AT> * SymTab<AT>::insert(string s)
    {
    ...
    }
    
    template <class AT>
    int SymTab<AT>::hash(string s)
    {
    ...
    }
    
    template <class AT>
    Node<AT> * SymTab<AT>::cons(Item<AT> *x, Node<AT> * y)
    {
        Node<AT> * ret = new Node<AT>;
        ret->info = x;
        ret->link = y;
        return ret;
    }
    
    template <class AT>
    SymTab<AT>::~SymTab()
    {
    ...
    }
    It compiles fine, but the linker is choking somewhere. Specifically, I get
    Everything's defined (although the SymTab constructor doesn't do anything since the only actual data is a fixed array), everything's properly included as far as I can tell... this is driving me nuts. Someone tell me I'm misspelling something somewhere.
     
  2. macrumors 601

    zimv20

    Joined:
    Jul 18, 2002
    Location:
    chicago
    #2
    been a while since i've done this stuff, but...

    are you calling the linker properly? it looks like it doesn't know about OpCode.o and symtab.o.

    also, from the coding sign, i guess i'm a little suprised that you have template classes that don't have constructors taking AT as an argument.
     
  3. macrumors 68040

    iSee

    Joined:
    Oct 25, 2004
    #3
    All template function definitions need to be in in the header file, either with the class delcaration or inlined after the class declaration.

    That is, everything in symtab.cpp needs to be put in symtab.h, either embedded in the class declaration or inline'd afterwards.

    Why? In order for a template class to be instantiated for a particular type, ALL the code needs to be available to the compiler. At their heart, templates are automated copy, seatch and replace engines. When you use SymTab<OpCode>, the compiler basically copies everything to do with SymTab from the header file and replaces AT with OpCode and then compiles it. It doesn't have access to the code in symtab.cpp, because that isn't included.
     
  4. macrumors member

    SamMiller0

    Joined:
    Aug 17, 2004
    Location:
    San Jose, CA
    #4
    Please post a tarball of your code and a makefile, I would like to take a look at it.
     
  5. macrumors 601

    zimv20

    Joined:
    Jul 18, 2002
    Location:
    chicago
    #5
    ahh, yeah, that's it. i forgot about that.
     
  6. thread starter macrumors 68000

    GeeYouEye

    Joined:
    Dec 9, 2001
    Location:
    State of Denial
    #6
    Yep, it was a combination of splitting it into two files (one bit of C++ I'd forgotten) and the templated constructor issue. Now to just get the rest of this code working...
     
  7. thread starter macrumors 68000

    GeeYouEye

    Joined:
    Dec 9, 2001
    Location:
    State of Denial
    #7
    And on that note, I'm trying to read in a hex value from a file. currently, I'm using ifstream infile; infile.open("file.txt"); infile >> hex >> myChar; and the 18 is only being read as 1, with the 8 being parsed later and leading to all sorts of screwups.

    Dang how I wish I could just use the Foundation framework.
     

Share This Page