Weird template problem

Discussion in 'Programmer's Corner' started by mentaaal, Oct 3, 2009.

  1. mentaaal

    Thread Starter Senior Member

    Oct 17, 2005
    451
    0
    Hey guys, I am having a really stupid template problem and I dont know why its happening. I am trying to create a linked list class as part of an assignment am using separate compilation as I always do to keep things tidy but it seems to be causing me some strange problems.

    Here is a simplified WORKING version of my class. Its only just for illustration really as there is nothing interesting in there yet:

    Link definition:
    Code ( (Unknown Language)):
    1. template<typename T>
    2. class Link
    3. {
    4. public:
    5.     Link()
    6.     {
    7.         start_ptr = 0;
    8.     }
    9.    
    10.  
    11. protected:
    12.     struct container    
    13.     {
    14.         T* holder;
    15.         container* next_ptr;
    16.     };
    17.     container * start_ptr;
    18. };
    Main() function
    Code ( (Unknown Language)):
    1. #include "Link.h"
    2.  
    3. int main()
    4. {
    5.     Link<int> test;
    6.  
    7.  
    8.     return 0;
    9. }
    10.  
    And now using separate compilation:
    Link header:
    Code ( (Unknown Language)):
    1. class Link
    2. {
    3. public:
    4.     Link();
    5.    
    6. protected:
    7.     struct container    
    8.     {
    9.         T* holder;
    10.         container* next_ptr;
    11.     };
    12.     container * start_ptr;
    13. };
    Link definion:
    Code ( (Unknown Language)):
    1. #include "Link.h"
    2.  
    3. template<typename T>
    4. Link<T>::Link()
    5. {
    6.     start_ptr = 0;
    7. }
    Main()
    Code ( (Unknown Language)):
    1. #include "Link.h"
    2.  
    3.  
    4. int main()
    5. {
    6.     Link<int> test;
    7.  
    8.  
    9.     return 0;
    10. }
    11.  
    12.  
    The error:
    Code ( (Unknown Language)):
    1. 1>------ Build started: Project: test link, Configuration: Debug Win32 ------
    2. 1>Compiling...
    3. 1>Link definition.cpp
    4. 1>Linking...
    5. 1>test link.obj : error LNK2019: unresolved external symbol "public: __thiscall Link<int>::Link<int>(void)" (??0?$Link@H@@QAE@XZ) referenced in function _main
    6. 1>Z:\College\Year 3\Programming\test link\Debug\test link.exe : fatal error LNK1120: 1 unresolved externals
    7. 1>Build log was saved at "file://z:\College\Year 3\Programming\test link\test link\Debug\BuildLog.htm"
    8. 1>test link - 2 error(s), 0 warning(s)
    9. ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

    interestingly, i also made a function that returns a pointer to a container struct (i.e. container *) and this causes an error unless i put define the struct container first. I.e. put the private stuff before the public stuff in the class definition..
    any thoughts on this?
     
    Last edited: Oct 3, 2009
  2. someonesdad

    Senior Member

    Jul 7, 2009
    1,585
    141
    You don't say what compiler you're using, give file names and their contents, nor give a makefile for the build -- these things are just as important as the code. Do you see that you've provided code for the constructor twice? This should have resulted in some kind of error message.

    I put the following in a.h:

    Code ( (Unknown Language)):
    1.  
    2. template<typename T>
    3. class Link
    4. {
    5. public:
    6.     Link()
    7.     {
    8.         start_ptr = 0;
    9.     }
    10.  
    11. protected:
    12.     struct container
    13.     {
    14.         T* holder;
    15.         container* next_ptr;
    16.     };
    17.     container * start_ptr;
    18. };
    19.  
    and the following in a.cpp:

    Code ( (Unknown Language)):
    1.  
    2. #include "a.h"
    3.  
    4. int main()
    5. {
    6.     Link<int> test;
    7.     return 0;
    8. }
    9.  
    The command line
    Code ( (Unknown Language)):
    1. g++ -Wall a.cpp
    resulted in an executable with no errors (MinGW version 3.4.5).

    A key to figuring out what is wrong with your code is giving the error message rapt attention. In your case, the code appears to be compiling fine but failing at the link. An unresolved external means there's a symbol used in the program and the compiler/linker can't figure out what to use for it. A common cause of this is leaving out a file that contains the definition of the symbol.
     
  3. mentaaal

    Thread Starter Senior Member

    Oct 17, 2005
    451
    0
    Hi and thank you for the reply. Well i am using Visual C++ 2005 express edition.

    You will see two versions of the constructor because this is the whole point of my question. The example that you tried was the one that I said was working just fine. The problem that I am having is when I try to use separate compilation and define the constructor in a different file altogether.You will also see that when I did this, I only included the prototype for the Link constructor in the header file.
     
  4. someonesdad

    Senior Member

    Jul 7, 2009
    1,585
    141
    Then please read the rest of my post and explain how you're compiling things. Don't expect people to guess important details you leave out -- make it easy for a responder to duplicate what you're doing. Also, it's a good habit to try building your code with more than one compiler. You'll learn more about portability and sometimes the error messages can be better.
     
  5. mentaaal

    Thread Starter Senior Member

    Oct 17, 2005
    451
    0
    What file names are you wanting? I am not currently writing anything or reading anything from an external file. The file name of the header file I am using is visible in the #include directive in the cpp file. In relation to how I am building it, all I am doing is building the program from the build button in the software I am using.

    I didn't give a makefile because I simply do not know what one is!
    I dont expect anyone to guess anything, I assume that someone might read the code and see if they know what the problem is, that's as far as my assumptions go.
     
  6. Mark44

    Well-Known Member

    Nov 26, 2007
    626
    1
    Mentaaal,
    In your separate compilation example, you show three files. The first one you identify as Link header (Link.h). The third one contains your main function. The second one you identify as Link definition (Link.cpp?). It would appear that VS doesn't know that this file is part of your project, which seems to be why you are getting the unresolved external symbol link error.
     
  7. someonesdad

    Senior Member

    Jul 7, 2009
    1,585
    141
    mentaaal, I'm sorry if I frustrated you. Let me explain where I was coming from. You said you're using a Microsoft compiler, so my ability to help there is limited, as I don't use MS compilers. Personally, I find the "all-in-one" IDEs to be hard to use, as each one is different and it's not clear what they do behind the scenes.

    There is no standard way to do things, of course, but the most universally understood is probably command line compilation, often done with makefiles or other automated building tools. These are tools that can be told "make this executable from these object files; make these object files from these source code files; etc.". They also can handle the details of dependencies, which means, for example, if one file changes, another file that depends on it must be rebuilt.

    The IDE you are using will do exactly the same tasks, but may not make how it does it apparent to the user. The Microsoft GUI tools used to use makefiles built with Microsoft's nmake, but that was a decade or two ago and things might not be done that way anymore.

    To make things most clear to people about how your software is being built, it's best to provide a command line that show's how it's being done. For example, a program might have a main.cpp file and two supporting files, unit1.cpp and unit2.cpp. A command line to build them might be:
    Code ( (Unknown Language)):
    1. g++ -Wall -g main.cpp unit1.cpp unit2.cpp
    The -Wall and -g are options to the compiler that tell it how to behave (compilers can have hundreds of different options). There are no standards, so every compiler uses different option letters. In the example I gave, "g++" is the GNU C++ compiler's name. The Borland compiler was "bcc" and the Microsoft compiler was "cl".

    Traditional files and command lines are pretty important and fundamental -- see chapter 9 of Stroustrup. This can be fairly heavy going for beginners, which is one advantage of the IDEs -- they help hide this complexity from the beginner. However, these units of compilation (the files) are "the coin of the realm"; that's why I asked for clarification.
     
  8. mentaaal

    Thread Starter Senior Member

    Oct 17, 2005
    451
    0
    Thank you for taking the time to clarify what a makefile is. I did try and google it after you mentioned it but i didnt get anything quite so clear as what you have said. I have very little experience with command line compilers but I am making the effor to familiarise myself with Linux and I see that it is quite convenient to use the g++ compiler.

    Let me just clarify where I am with this small problem:
    I have verified that the problem I am having is more than likely to do with some aspect of how I am coding the definition and not to actually linking it. I can say this as i have put in a dummy class into the definition and header files (seen below). The dummy class, in this case just called temp has no problem at all when i comment out the definition of the Link constructor (and obvoiusly put it back in the header file.)

    I will consult with my lecturer tomorrow and if we can find the problem I will surely let you guys know.
    header file: link.h
    Code ( (Unknown Language)):
    1. #include <iostream>
    2. using namespace std;
    3. template<typename T>
    4. class Link
    5. {
    6.     protected:
    7.     struct container    
    8.     {
    9.         T* holder;
    10.         container* next_ptr;
    11.     };
    12.     container * start_ptr;
    13.  
    14.  
    15. public:
    16.     Link()
    17.     :start_ptr(NULL)
    18.     {}
    19.     container* search_node(int)
    20.         {
    21.             int num = 0;
    22.             container* temp = NULL;
    23.             if(start_ptr==NULL)
    24.             {
    25.                 found = NULL;
    26.             }
    27.             else
    28.             {
    29.                 temp = start_ptr;
    30.                 while(temp->next_ptr != NULL &&  num != loc)
    31.                 {
    32.                     temp = temp->next_ptr;
    33.                     num++;
    34.                 }
    35.                 return ((num == loc)?temp:NULL);
    36.             }
    37.         }
    38.    
    39.  
    40. };
    41.  
    42. class temp
    43. {
    44. public:
    45.     int return_num(int);
    46. };
    47.  
    definition file: link_definition.cpp
    Code ( (Unknown Language)):
    1. #include "Link.h"
    2.  
    3. /*template <typename T>
    4. Link<typename T>::Link()
    5. :start_ptr(NULL)
    6. {}*/
    7.  
    8. int temp::return_num(int num)
    9. {
    10.     return num;
    11. }
    main file test link.cpp
    Code ( (Unknown Language)):
    1. //#include <iostream>
    2.  
    3. //using namespace std;
    4. #include "Link.h"
    5.  
    6.  
    7. int main()
    8. {
    9.     Link<int> test;
    10.  
    11.     temp Test;
    12.    
    13.     cout << "Returned number after sending in 5 is: " << Test.return_num(5) << endl;
    14.  
    15.  
    16.     return 0;
    17. }
    18.  
    19.  

    interestingly, i have also noticed other strange things going on. Like for example, as you can see I have put the private members before the public. I did this as I get an error saying that the member in question wasn't defined.
     
  9. someonesdad

    Senior Member

    Jul 7, 2009
    1,585
    141
    I do suggest you learn to compile your files at the command line. Then you'll be able to post code that others can try and compile the same way you are.

    Most compilers will let you compile your code in "vanilla" fashion by a command such as

    xxx main.cpp other.cpp

    where xxx is the command to invoke the compiler.

    Frankly, for simple projects, this is much easier than messing around with an IDE.
     
  10. mentaaal

    Thread Starter Senior Member

    Oct 17, 2005
    451
    0
    Ay Ay capitain! Windows IDE was the first compiler I was exposed to and havent really used anything else. I guess I have become lazy in that I find the syntax highlighting and code completion to be very handy. If i get no answer from my lecturer about it I will do as you suggest.
    Thanks
     
  11. someonesdad

    Senior Member

    Jul 7, 2009
    1,585
    141
    That's very understandable. But here's something to consider. About 20 years ago I changed my career from thin film physics to software engineering because I saw that more job requisitions at the company site I was working at were for CS types rather than physicists. One of my managers got me a job in a disk drive controller group that did firmware. We all worked on UNIX systems and I asked one of the experienced persons what editor I should use (the usual choices were vi or emacs). He suggested vi because it was on all UNIX boxes with no setup work. Certainly emacs can be found and set up for most UNIX boxes too, but looking back, I consider the vi advice as excellent, as I can be up and working on virtually any system in a matter of a minute or two. My current system is a Windows XP box (I only use it because my customers use it); I use it with cygwin to give me a UNIX-like environment.

    About 15 years ago I started using the vim editor, a vi clone. I've stuck with it because it's an excellent editor and available for any platform I'd be likely to work on. Warning: if you give vi a try, stick with it -- it's quite unfriendly to beginners. But experienced users can be very efficient with it -- when I'm in a hurry, I can edit so fast that even experienced software engineers can't follow what I'm doing (even though I'm a geezer :)). I've also seen some experienced folks using emacs do the same thing. I've never seen this happen with any Windows or IDE editor.

    Here's the point: a few years back I took a contract software engineering job with a company. They were using Linux boxes for their C++ development. I walked in, sat down, and in a minute or two was working on code. Since they were using the GNU toolchain, I could also do my work on HPUX boxes and Windows computers. This would have been impossible if I was using a proprietary, platform-specific tool like Microsoft's compiler. (Important note: this is not a statement about the goodness or badness of Microsoft's tool; rather, it's a comment on being effective in multiple environments.) If you think you'll only work in e.g. a Windows environment, then it's specious advice.

    Over the years, I've tried numerous editors like CodeWright, Visual SlickEdit, UltraEdit, Notepad++ (the companies I've worked for would buy me any tool I wanted). They're all good editors with good features, but I usually abandon them within a few days and go back to vim. vim has syntax highlighting, which is useful, although I often turn it off.

    The code completion sounds like it would be very useful -- and it is, under certain circumstances. One of them is when you're doing programming using a huge library of functions (e.g., Windows32 functions) and you can't remember all the function parameters). However, I've worked with those tools and find myself turning the code completion off, as I find it gets in my way. When I use vim, I just build a tags file (using exhuberant ctags, a great tool) and can instantly get to any function definition to look at the parameters; that's a reasonably good substitute for code completion. (If I need lots of library stuff, I just have a cron job build a tags file on /usr/include every night.) No doubt someone has put together a code completion tool together for vim, but I find no need for it, so I haven't sought it out.

    Of course, YMMV, so you'll likely go your own path. But it is useful to hear what others have found; that advice can help you form your own directions. And I'm not proselytizing vi -- whatever tools you use, make sure they're powerful and that you spend significant effort on using them effectively. Example: I've seen smart software engineers use powerful editors by hunt-and-peck typing and be agonizingly slow at their jobs. I've also seen them not use the powerful command line editing tools of their shell -- they'd make a mistake, then start to type the whole bloody long command over again! Lesson: the expert craftsman learns to use his tools quite effectively by study and practice.
     
  12. darenw5

    Active Member

    Feb 2, 2008
    45
    0
Loading...