This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

C++ nested classes linker error

Other Parts Discussed in Thread: MSP430F1222

Hi,

I am writing a C++ project on MSP430F1222 using IAR.
My problem is related to the nested class named "Queue".

When I compile the following code, the compilation stage passes fine but I receive the following four linker errors:

Error[e46]: Undefined external "I2C::Queue<tMESSAGE>::GetNumberOfMessagesInQueue()" referred in I2C ( C:\alon\projects\FS project\MSP430\Debug\Obj\I2C.r43 )

Error[e46]: Undefined external "I2C::Queue<tMESSAGE>::PushQueue(_tMESSAGE &)" referred in I2C ( C:\alon\projects\FS project\MSP430\Debug\Obj\I2C.r43 )

Error[e46]: Undefined external "I2C::Queue<tMESSAGE>::PopQueue()" referred in I2C ( C:\alon\projects\FS project\MSP430\Debug\Obj\I2C.r43 )

Error[e46]: Undefined external "I2C::Queue<tMESSAGE>::IncrementHead()" referred in I2C ( C:\alon\projects\FS project\MSP430\Debug\Obj\I2C.r43 )

I assume all the four similar errors are caused by the same type of mistake.
How can I fix it?

Thanks in advance,

Alon


The code:
=======

Queue.h
======
#include "typedef.h"

// cyclic queue

template <class T>

class Queue

{

private:


T *array; // preferred to be of size of whole multiplications of incrementSize
u_int_8 maxSize;
u_int_8 incrementSize; // in T-type elements

// queueHead == queueTail means queue is empty
// (queueTail == queueHead - 1 || queueHead == 0 && queueTail == tMESSAGE_QUEUE_SIZE) means queue is full
u_int_8 head; // points to current message that is being processed
u_int_8 tail; // points to the position where the next message will be written to

void IncrementIndex(u_int_8 &index);

public:


Queue()
{};

void init (T *i, u_int_8 j, u_int_8 k)
{
array = i;
maxSize = j;
incrementSize = k;
}

u_int_8 GetNumberOfMessagesInQueue();
void PushQueue(T &data);
T &PopQueue();
void IncrementHead();

};

Queue.c
======
#include "Queue.h"

template <class T>
u_int_8 Queue <T>::GetNumberOfMessagesInQueue()
{

if (tail >= head){


return tail - head;


}
else{


return maxSize - head + 1 + tail;


}


}

// index can be 'head' or 'tail'
template <class T>
void Queue <T>::IncrementIndex(u_int_8 &index)
{


// increment index
if (index + (incrementSize << 1) <= maxSize){ // <<1 for *2


index += incrementSize;


}
else{


index = 0;


}
}

template <class T>
void Queue <T>::IncrementHead()
{


IncrementIndex(head);


}

template <class T>
void Queue <T>::PushQueue(T &data)
{


array[tail] = data;
IncrementIndex(tail);


}

template <class T>
T &Queue <T>::PopQueue()
{


return array[head];


}

I2C.h
====
typedef struct _tMESSAGE{


u_int_16 Address;
bool WriteRead;
u_int_8 numberOfDataPieces;
tDATA_PIECE *data;
bool IsStop;
bool AckPollingFlag;


} tMESSAGE;

class I2C
{


private:


// message queue
tMESSAGE messageQueue[MESSAGE_QUEUE_SIZE + 1];
#include "Queue.h"
static Queue <tMESSAGE> messaQueue;

friend __interrupt void ISR_TIMER_A_CC0();

public:


I2C()
{


messaQueue.init(messageQueue, MESSAGE_QUEUE_SIZE, 1);


};
}

I2C.c
====
#include "typedef.h"
#include "Queue.h"
#include "I2C.h"

// static variables
I2C::Queue <tMESSAGE> I2C::messaQueue;

// TIMER_A CC0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void ISR_TIMER_A_CC0()
{


static u_int_8 dataPieceCounter;
static s_int_8 bit, dataByteCounter;
static BOOL addressOrData; // 0=address; 1=data


if (I2C::messaQueue.PopQueue().Address & 1){


I2C::setSDA();


}

I2C::messaQueue.IncrementHead(); // increment queue head


}

  • The problem is that the code of functions like "Queue<T>::PopQueue()" is available only in Queue.c, but that the compiler doesn't know that an instantiation for tMESSAGE is needed when that file is compiled. You have to either move the implementation into the header, or explicitly instantiate the template for tMESSAGE in the .c file.

**Attention** This is a public forum