/* I'm stuck!  Here is what I consider to be a perfectly running program that uses
   an array ( TArray ) template to hold arrays of objects.  Its just about your
   classic text book example.  Its pretty well stripped down to nothing to 
   illustrate my problem.  I simply don't know how to break it out into .cpp and 
   .h implementation and header files.  Been trying all day.  The output of this 
   program which does work follows.  It just uses a real simple class object as an
   example of something to contain, i.e., class CClient with a char* first name, a 
   char Sex, i.e., 'm', 'f', and an int age.  Its a 16 byte class.

   You can see with my template TArray class I didn't inline the members preparatory
   to seperating it out into TArray.cpp and TArray.h.  However, when I attempt to
   break my CClient and TArray objects into seperate implementation and header files
   I simply can't get it to link.  Not a compile error mind you, a link error!

   Anyway, here is the working program, and after this I'll provide the one that
   doesn't work with seperate files, i.e.,...

   
   CClient.h,  CClient.cpp
   TArray.h,   TArray.cpp
   Main.cpp

   In that order.  Please, can someone tell me what I'm doing wrong here?  I'm lost,
   demoralized, humiliated, and mystified.  Did I mention unhappy?

*/

#include <stdio.h>
#include <string.h>

class CClient
{
 public:
 CClient(){printf("CClient Uninitialized Constructor Called!\n");}
 ~CClient(){printf("CClient Destructor Called!\n");}

 void setclient(char* szName, char cSex, int iAge)
 {
  strcpy(m_szName,szName);
  m_Sex=cSex;
  m_Age=iAge;
 }

 void display(void)
 {
  printf("%s\t%c\t%d\n", this->m_szName, this->m_Sex, this->m_Age);
 }

 private:
 char m_szName[11];
 char m_Sex;
 int  m_Age;
};


template<class T, unsigned int iMaxCount> class TArray
{
 public:
 TArray(const T* obj, int iCount);
 void dump(void);
 unsigned int count(void);
 unsigned int capacity(void);

 private:
 unsigned int m_Top;
 T x[iMaxCount];
};

template<class T, unsigned int iMaxCount> TArray<T,iMaxCount>::TArray(const T* obj, int iCount)
{
  this->m_Top=iCount;
  for(unsigned int i=0;i<this->m_Top;i++)
      x[i]=obj[i];
}

template<class T, unsigned int iMaxCount> void TArray<T,iMaxCount>::dump(void)
{
 for(unsigned int i=0; i<m_Top; i++)
      x[i].display();
}

template<class T, unsigned int iMaxCount> unsigned int TArray<T,iMaxCount>::count(void)
{
 return m_Top;
}

template<class T, unsigned int iMaxCount> unsigned int TArray<T,iMaxCount>::capacity(void)
{
 return sizeof(x)/sizeof(x[0]);
}

void Run(void)
{
 CClient c[6];
 c[0].setclient("Fred",'m',57);
 c[1].setclient("Elsie",'f',56);
 c[2].setclient("Mark",'m',60);
 c[3].setclient("Joanne",'f',59);
 c[4].setclient("John",'m',48);
 c[5].setclient("Mary",'f',46);
 TArray<CClient,8> ar1(c,6);
 ar1.dump();
 printf("ar1.capacity()  = %u\n",ar1.capacity());
 printf("ar1.count()     = %u\n",ar1.count());
}

int main(void)
{
 Run();
 getchar();

 return 0;
}

/*
Perfectly Working Output From Above
=========================================

CClient Uninitialized Constructor Called!
CClient Uninitialized Constructor Called!
CClient Uninitialized Constructor Called!
CClient Uninitialized Constructor Called!
CClient Uninitialized Constructor Called!
CClient Uninitialized Constructor Called!
CClient Uninitialized Constructor Called!
CClient Uninitialized Constructor Called!
CClient Uninitialized Constructor Called!
CClient Uninitialized Constructor Called!
CClient Uninitialized Constructor Called!
CClient Uninitialized Constructor Called!
CClient Uninitialized Constructor Called!
CClient Uninitialized Constructor Called!
Fred    m       57
Elsie   f       56
Mark    m       60
Joanne  f       59
John    m       48
Mary    f       46
ar1.capacity()  = 8
ar1.count()     = 6
CClient Destructor Called!
CClient Destructor Called!
CClient Destructor Called!
CClient Destructor Called!
CClient Destructor Called!
CClient Destructor Called!
CClient Destructor Called!
CClient Destructor Called!
CClient Destructor Called!
CClient Destructor Called!
CClient Destructor Called!
CClient Destructor Called!
CClient Destructor Called!
CClient Destructor Called!
*/

And here are the pieces of the above program broken out into
a Main.cpp and CClient and TArray implmentation and header
files which I'm way to dumb to get to compile. I'm using
CodeBlocks. Here is the linker error I just can't figure
out...

Compiling: CClient.cpp
Linking console executable: CClient6.exe
C:\Code\CodeBlks\COM\Templates\CClient6\.objs\main.o:main.cpp:(.text+0x17c):
undefined reference to `TArray<CClient, 8u>::TArray(CClient const*, int)'
collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 1 seconds)
1 errors, 0 warnings

//CClient.h

class CClient
{
 public:
 CClient();
 ~CClient();
 void setclient(char*, char, int);
 void display(void);

 private:
 char m_szName[11];
 char m_Sex;
 int  m_Age;
};
//CClient.cpp
#include <stdio.h>
#include <string.h>
#include "CClient.h"

CClient::CClient()
{
 printf("Default Uninitialized Constructor Called!\n");
}

CClient::~CClient()
{
 printf("CClient Destructor Called!\n");
}

void CClient::setclient(char* szName, char cSex, int iAge)
{
 strcpy(m_szName,szName);
 m_Sex=cSex;
 m_Age=iAge;
}

void CClient::display(void)
{
 printf("%s\t%c\t%d\n", this->m_szName, this->m_Sex, this->m_Age);
}
//TArray.h

template<class T, unsigned int iMaxCount> class TArray
{
 public:
 TArray(const T obj[], int iCount);  //constructor takes array of objs & count
 void dump(void);                    //dumps array of objects
 unsigned int count(void);           //present count of objects held
 unsigned int capacity(void);        //maximum capacity that was set at instance initialization

 private:
 unsigned int m_Top;
 T x[iMaxCount];
};
//TArray.cpp
#include "TArray.h"

template<class T, unsigned int iMaxCount> TArray<T,iMaxCount>::TArray(const T obj[], int iCount)
{
 this->m_Top=iCount;                       //I think this is a constructor.  Its designed to
 for(unsigned int i=0;i<this->m_Top;i++)   //take a pointer to an array of objects, and a
     x[i]=obj[i];                          //count of aforsaid objects and store them in its
}                                          //x strorage variable.

template<class T, unsigned int iMaxCount> void TArray<T,iMaxCount>::dump(void)
{
 for(unsigned int i=0; i<m_Top; i++)
     x[i].display();
}

template<class T, unsigned int iMaxCount> unsigned int TArray<T,iMaxCount>::count(void)
{
 return m_Top;
}

template<class T, unsigned int iMaxCount> unsigned int TArray<T,iMaxCount>::capacity(void)
{
 return sizeof(x)/sizeof(x[0]);
}
//Main.cpp
#include <stdio.h>
#include <string.h>
#include "CClient.h"
#include "TArray.h"

void Run(void)  //This way I'll get destructor calls
{
 CClient c[6];                    //Allocate six CClients
 c[0].setclient("Fred",'m',57);   //and fill them with some
 c[1].setclient("Elsie",'f',56);  //arbitrary test data.
 c[2].setclient("Mark",'m',60);   //Then allocate a TArray
 c[3].setclient("Joanne",'f',59); //template object to
 c[4].setclient("John",'m',48);   //contain them.  My intent
 c[5].setclient("Mary",'f',46);   //wast to set up the TArray
 TArray<CClient,8> ar1(c,6);      //max capacity to 8 even
 puts("Running!");                //though I've only got 6
}                                 //CClients.

int main(void)
{
 Run();         //when Run exits
 getchar();

 return 0;
}

I only skimmed your question, but it sounded like:
http://parashift.com/c++-faq-lite/templates.html#faq-35.12

[edit]Short fix?

//Main.cpp
#include <stdio.h>
#include <string.h>
#include "CClient.h"
#include "TArray.cpp"

Thanks Dave! I just skimmed that doc, but it does look like my problem. Will work on it today.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.