Linking error, help?

Started by
6 comments, last by 3dmodelerguy 18 years, 11 months ago
hey i am trying to make a custom link list with classes and templates and I have come to these 2 error:

------ Build started: Project: CustomList, Configuration: Debug Win32 ------

Compiling...
clist.cpp
Linking...
main.obj : error LNK2019: unresolved external symbol "public: __thiscall CList::CustomList<char>::~CustomList<char>(void)" (??1?$CustomList@D@CList@@QAE@XZ) referenced in function _main
main.obj : error LNK2019: unresolved external symbol "public: __thiscall CList::CustomList<char>::CustomList<char>(void)" (??0?$CustomList@D@CList@@QAE@XZ) referenced in function _main
Debug/CustomList.exe : fatal error LNK1120: 2 unresolved externals

Build log was saved at "file://c:\Documents and Settings\ryan\My Documents\Visual Studio Projects\CustomList\Debug\BuildLog.htm"
CustomList - 3 error(s), 0 warning(s)


---------------------- Done ----------------------

    Build: 0 succeeded, 1 failed, 0 skipped

here is my source code i have: clist.h:

#ifndef CLIST_H
#define CLIST_H

namespace CList
{
	template< class t >
	class CustomList
	{
	public:
		CustomList();
		CustomList( t el );
		~CustomList();
		void Print();

	private:
		t _info;
		CustomList* _next; 
	};
}

#endif

clist.cpp:

#include <iostream>
#include "clist.h"

template< class t >
CList::CustomList< t >::CustomList()
{

}
template< class t >
CList::CustomList< t >::CustomList( t el )
{
	_info = el;
}
template< class t >
CList::CustomList< t >::~CustomList()
{

}
template< class t >
void CList::CustomList< t >::Print()
{
	std::cout << _info << std::endl;
}

main.cpp

#include <iostream>
#include "clist.h"

int main()
{
	CList::CustomList< char > charlist;
	return 0;

}

it is when i have the line that adds the CustomList object in the code is when i get the error, any help would be great. thanks
Advertisement
A template class' member functions must be visible from the instanciation point.

Long story short: put them in the header file.

When the compiler is processing clist.cpp, it doesn't know which T the class will be used for (you may tell it by adding class CList<char>; in there to force instanciation, but that kinda defeats the purpose). So it doesn't actually generate any code for them.

When the compiler is processing main.cpp, it doesn't have access to the source code for the member functions anymore, so it cannot instanciate them with T=char.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
I am sorry but i dont understand, what do you mean must be visable? I tried with the class members in the public instead of private but that does not help, could you please try to explian a little more?
Quote:Original post by 3dmodelerguy
I am sorry but i dont understand, what do you mean must be visable? I tried with the class members in the public instead of private but that does not help, could you please try to explian a little more?


A compiler only processes a file at a time. Outside of the generated object files that eventually get linked together, there is no communication happening between the different runs of the compiler over the individual source files (that's the "separate compilation" model). A translation unit is composed of the .cpp file you're compiling, along with all the headers it includes (recursively). That translation must contain all the information the compiler needs to generate the object file.

When you declare a class template, you omit part of the information needed to compile the class, namely the template parameters so, obviously, the compiler cannot generate code for it yet. All it does is syntax-check it (which is why you need to add the typename keyword when using a dependent type, as the C++ grammar is ambiguous at that point).

It is only when you actually create a variable of that type that the compiler actually generates code for the class, using the appropriate parameters. The compiler cannot do anything with clist.cpp, since nowhere in its translation unit do you tell it what version of CustomList it should generate (which is what my previous comment was alluding to).

Additionally, a template class' member function are only compiled if they are actually used (this is, among other things, because not all member functions might work for all possible parameterizations of the class).

The problem with your code is that you have squirreled away the definition for the member functions into a separate file, which is not part of the main.cpp translation unit. The compiler sees that you are using CustomList<char>'s constructor so, at that point, it actually tries to compile it and generate the code for that instanciation of the class template. Unfortunately, the code for that constructor is not available. The compiler hasn't "seen" it in the current translation unit (hence it is not "visible").

The only way, with the current generation of compilers, to fix that problem is to include the member function definitions in every translation unit that is going to use the class. The simplest way to do that is, obviously, to put them in the header file that defines the class template. That is, you need to move the contents of clist.cpp over to clist.h.

As a final note, visibility and accessibility are two different concepts. The private members of a class are visible, but not accessible. When you try to access them improperly, the compiler tells you that they are private, instead of telling you that they do not exist (as it would for class, function or variable that hasn't been yet declared in the current translation unit).
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Ok I understand and that works. The problem it the this is the way i have been doning my classes since i started. It is something the has to do with the template classes or classes in general?
Hey plus i have another error with almost the same code the some code. i am getting this error

c:\Documents and Settings\ryan\My Documents\Visual Studio Projects\CustomList\main.cpp(6) : error C2061: syntax error : identifier '__ctor'


when i try to allocate the memory using this line of code

CList::CustomList< char > *charlist = new CList::CustomList< char >::CustomList( 'r' );

I looked at the VS help for that code error number but did not help me.
Quote:Original post by 3dmodelerguy
Hey plus i have another error with almost the same code the some code. i am getting this error

c:\Documents and Settings\ryan\My Documents\Visual Studio Projects\CustomList\main.cpp(6) : error C2061: syntax error : identifier '__ctor'


when i try to allocate the memory using this line of code

CList::CustomList< char > *charlist = new CList::CustomList< char >::CustomList( 'r' );

I looked at the VS help for that code error number but did not help me.


The call you want to create the CustomList is this one:
CList::CustomList< char > * charlist = new CList::CustomList< char >('r')
You don't need to explicitly call the constructor, simply putting the parentheses with the arguments behind the type is enough.
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!
Hey thanks, I though i tried that but i guess not.

This topic is closed to new replies.

Advertisement