Jump to content
  • Advertisement
Sign in to follow this  
Jouei

Linking Errors

This topic is 3451 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Langauge: Cpp Compiler: VC++ Express 2008 I just finshed reading a articul and doing a tutorial for a matrix container Eg Dynacmicaly Allcoated Multi dimenstional Arrays. Now i am currently getting these to linking errors and i am unsure as to why i will post bolth the Code for the Matrix class and where the error is comming from. First the Matrix Header and then Cpp
#ifndef MATRIX_H
#define MATRIX_H

#include <vector>
 
template<typename T>  // See section on templates for more

class MATRIX 
{
public:
MATRIX(unsigned nrows, unsigned ncols);
// Throws a BadSize object if either size is zero
class BadSize { };
// These throw a BoundsViolation object if i or j is too big
class BoundsViolation { };

// Access methods to get the (i,j) element:
	  T& operator() (unsigned i, unsigned j);       // &#8592; subscript operators often come in pairs
const T& operator() (unsigned i, unsigned j) const; // &#8592; subscript operators often come in pairs

unsigned nrows() const;  // #rows in this MATRIX
unsigned ncols() const;  // #columns in this MATRIX

private:
std::vector<std::vector<T> > data_;
};

#endif MATRIX_H



#include "MATRIX.h"

template<typename T>
inline unsigned MATRIX<T>::nrows() const
{ return data_.size(); }

template<typename T>
inline unsigned MATRIX<T>::ncols() const
{ return data_[0].size(); }

template<typename T>
inline T& MATRIX<T>::operator() (unsigned row, unsigned col)
{
if (row >= nrows() || col >= ncols()) throw BoundsViolation();
return data_[row][col];
}

template<typename T>
inline const T& MATRIX<T>::operator() (unsigned row, unsigned col) const
{
if (row >= nrows() || col >= ncols()) throw BoundsViolation();
return data_[row][col];
}

template<typename T>
MATRIX<T>::MATRIX(unsigned nrows, unsigned ncols)
: data_ (nrows)
{
if (nrows == 0 || ncols == 0)
 throw BadSize();
for (unsigned i = 0; i < nrows; ++i)
 data_.resize(ncols);
} 


And now the two Sources files where i implement the Matrix code.

#ifndef RENDER_H
#define RENDER_H	

#include <windows.h>
#include "Matrix.h"

//Make ourselves a Quick Surface
typedef MATRIX <CHAR_INFO> SURFACE;

class RENDER
{
	public:
	RENDER(unsigned int ScreenWidth, unsigned int ScreenHeight);
	~RENDER(){if(MainScreen)delete MainScreen;}

	bool SetupConsole(std::string WindowName);
	void ClearScreen(WORD Color);
	bool Flip();

	private:
	SURFACE * MainScreen;
	HANDLE Output;
	unsigned int Width;
	unsigned int Height;
};

#endif RENDER_H


#include "Render.h"

bool RENDER::SetupConsole(std::string WindowName)
{
	Output = GetStdHandle(STD_OUTPUT_HANDLE);
	if(!Output){return false;}
	SetConsoleTitle(WindowName.c_str());
	return true;
}

RENDER::RENDER(unsigned int ScreenWidth, unsigned int ScreenHeight)
{
MainScreen = new MATRIX<CHAR_INFO>(ScreenWidth,ScreenHeight);
Width = ScreenWidth;
Height = ScreenHeight;
}

void RENDER::ClearScreen(WORD Color)
{
	if(!MainScreen)return;
	SURFACE Work = *MainScreen;

	for(unsigned int Cols = 0; Cols < Height; Cols++)
	{
		for(unsigned int Rows = 0; Rows < Width; Rows++)
		{
			Work(Rows,Cols).Attributes = Color;
			Work(Rows,Cols).Char.UnicodeChar = 0;
		}
	}

}

bool RENDER::Flip()
{

	COORD dwBufferSize = { Width,Height }; 
	COORD dwBufferCoord = { 0, 0 }; 
	SMALL_RECT rcRegion = { 0, 0, Width-1, Height-1 }; 
	if(!WriteConsoleOutput( Output, (CHAR_INFO *)MainScreen, dwBufferSize,dwBufferCoord, &rcRegion ))
	{
	return false;
	}

	return true;
}


And it appears the two lines that cause the linking errors SURFACE Work = *MainScreen; and MainScreen = new SURFACE(ScreenWidth,ScreenHeight); The linking Errors are as follows, I would also like to point out that there are no warning generated with this code. Render.obj : error LNK2001: unresolved external symbol "public: __thiscall MATRIX<struct _CHAR_INFO>::MATRIX<struct _CHAR_INFO>(unsigned int,unsigned int)" (??0?$MATRIX@U_CHAR_INFO@@@@QAE@II@Z) 1>Render.obj : error LNK2001: unresolved external symbol "public: struct _CHAR_INFO & __thiscall MATRIX<struct _CHAR_INFO>::operator()(unsigned int,unsigned int)" (??R?$MATRIX@U_CHAR_INFO@@@@QAEAAU_CHAR_INFO@@II@Z) Well thanks for any responses and no libs are required for the code i currently have or the matrix class. Regards Jouei

Share this post


Link to post
Share on other sites
Advertisement
CHAR_INFO is defined in a windows hearder file it is a character bit for a console appliication.

The specific file is WinCon.h

typedef struct _CHAR_INFO {
union {
WCHAR UnicodeChar;
CHAR AsciiChar;
} Char;
WORD Attributes;
} CHAR_INFO, *PCHAR_INFO;

Regards Jouei

Share this post


Link to post
Share on other sites
Quote:
Original post by Carleone
Quote:
First the Matrix Header and then Cpp

You must define template functions inside header. Not in cpp file.


There are at least two ways so you don't have to:
  • Explicit Instantiation
  • the export-keyword, though only the edg frontend implements it

Share this post


Link to post
Share on other sites
Well that fixed the problem but is there a paticular reason that you can not have the functions defined in a cpp file.

I would just like to know the reason behind it so i understand where the problem stems from.

Regards Jouei.

Share this post


Link to post
Share on other sites
Quote:
phresnel
There are at least two ways so you don't have to:
* Explicit Instantiation
* the export-keyword, though only the edg frontend implements it


Explicit Instantiation.

Export Keyword.


The reason is that the compiler has to know how a template is defined, because at the time of the template definition it eventually contains typenames, so template are like big formulas with unknown values.

It can't guess what a template instantiation will look like, as a construct like e.g. "a * b" can be anything, ranging from multiplication of integers up to an overload of * onto some type, itself triggering the formatting of your harddrive.

So all in all, templates are templates, with unknowns. Because they can be expanded to anything, the compiler must know it. Like it has to know the definition of inline functions (don't confuse inline functions with template functions, template functions underly the same inlining rules as ordinary functions).


So, say you have a function template like

// foo.h
template <typename T> void foo (const T &t);



(let's assume its actual definition is in file "foodef.h") and have a line saying

foo (6);



the linker will look up whether it can find a definition of something that fits into "foo (int)" (also, following typecasting rules, a complex topic in itself). If it can't find anything, it will trigger an error. Note that this error comes during linking, not during compiling.

Say you have an additional cpp-file (i.e. another unit passed to the linker), you can say

#include "foo.h" // declaration
#include "foodef.h" // definition
template void foo <int> (const int &t);



, which will trigger the instantiation of the template and make it an externally visible symbol on linking. The next time you compile and link, the linker will find a symbol that fits into "foo (int)". This is called explicit instantiation.

Explicit instantiation has of course some disadvantages, too:
a) you as the programmer have to ensure you only instantiate once and only once for each type
b) if something is not instantiated yet on a specific type, you need to make the compiler know the definition of the template in use (e.g. by #include'ing foodef.h)


I highly recommend "C++ Templates: The Complete Guide" (Vandevoorde, Josuttis), the first 10 chapters should be easy for you :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!