I’m trying to learn how to use C++ templates, and I thought I was grasping it all ok until I decided to try to pass a template defined object variable as a function parameter. Having all kinds of troubles with that.

I’m using a typical example of a parameterizd array class. The members of the array are client objects with a name, gender, and age, i.e.,

Fred   m    56
Sue    f    46
Mary   f    21

Etc.

This class is CClient

class CClient          //CClients
{
 public:
 CClient();
 ~CClient();
 void SetName(CString s);
 void SetGender(char gender);
 void SetAge(int iAge);
 void input();
 void display(unsigned int ctr) const;

 private:
 CString m_Name;
 char    m_Sex;
 int     m_Age;
};

My template is an array that should be able to hold some number of these, i.e.,

template<class Tpl> class CArray
{
 public:
 CArray();
 ~CArray();
 
 bool AddNew(Tpl& pObj);        //adds a new Tpl to Carray object
 unsigned int get_size() const; //returns actual number in CArray
 void dump();                   //dumps objects to console
 
 private:
 unsigned int m_New;            //marks last/new object position
 Tpl x[MAX_SIZE];               //array of whatever
};

Actually, I have this part working. If you take a look at the CClient class above you’ll see an input() member function declaration. I had implemented that with a scanf() to get series of names, genders, and ages from the keyboard. I was calling that from main(). That got pretty tiresome entering all that data by hand repeatedly just to test the workings of the classes and so forth, so I decided to try to add a non-member plain ordinary function called AddData() to my program called from main() that would blow several CClients into the CArray without my having to keypunch them. Only thing is, I wanted to declare a CClient object, and a CArray object in main(), and pass these objects as parameters to my AddData() function like so…

Int main(void)
{
 CArray<CClient> Folks;
 CClient c;

 AddData(c, Folks);
 Folks.dump();
 getchar();

 return 0;
}

…and AddData() looks like this…

template<class Tpl>
void AddData(CClient& c, CArray<Tpl>& ar)
{
 c.SetName("Fred"),   c.SetGender('m'), c.SetAge(56),  ar.AddNew(c);
 c.SetName("Elsie"),  c.SetGender('f'), c.SetAge(55),  ar.AddNew(c);
 c.SetName("Mark"),   c.SetGender('m'), c.SetAge(60),  ar.AddNew(c);
 c.SetName("Joanne"), c.SetGender('f'), c.SetAge(59),  ar.AddNew(c);
 c.SetName("Alice"),  c.SetGender('f'), c.SetAge(61),  ar.AddNew(c);
 c.SetName("John"),   c.SetGender('m'), c.SetAge(62);  ar.AddNew(c);
}

Here is the whole program, which works fine and produces the following output…

Output:

CArray() Constructor Called!

0       Fred            m       56
1       Elsie           f       55
2       Mark            m       60
3       Joanne          f       59
4       Alice           f       61
5       John            m       62

~CArray() Destructor Called!

//Here Is The Working Program That Produces That Output

//template6        //this program works – using VC++ 6
#include <afx.h>
#include <stdio.h>
#define  MAX_SIZE 10


class CClient          //CClients
{
 public:
 CClient():m_Name("xxx"),m_Sex('x'),m_Age(0){/*puts("Constructor Called!");*/}
 ~CClient(){/*printf("Destructor Called!\n");*/}
 void SetName(CString s)     {this->m_Name=s;}
 void SetGender(char gender) {this->m_Sex=gender;}
 void SetAge(int iAge)       {this->m_Age=iAge;}

 void input()
 {
  char name[20], gender[2];
  int age;
  
  scanf("%s%s%d",name,gender,&age);
  this->m_Name=name;
  this->m_Sex=gender[0];
  this->m_Age=age;
 }

 void display(unsigned int ctr) const
 {
  CString s;
  if(this)
  {
     s.Format("%u\t%-10s\t%c\t%d\n",ctr,m_Name,m_Sex,m_Age);
     printf("%s",s);
  }
  else
  {
   s.Format("%s\t%s\t%s\t%s\n","Null","Null","Null","Null");
   printf("%s",s);
  }
 }

 private:
 CString m_Name;
 char    m_Sex;
 int     m_Age;
};


template<class Tpl> class CArray
{
 public:
 CArray(){puts("CArray() Constructor Called!\n");this->m_New=0;}
 ~CArray(){puts("~CArray() Destructor Called!");}

 bool AddNew(Tpl& pObj)
 {
  if(this->m_New<MAX_SIZE)
  {
     x[m_New]=pObj;
     this->m_New++;
     return true;
  }

  return false;
 }

 unsigned int get_size() const
 {
  return this->m_New;
 }

 void dump()
 {
  unsigned int i;
  for(i=0;i<this->get_size();i++)
      x[i].display(i);
 }

 private:
 unsigned int  m_New;
 Tpl x[MAX_SIZE];
};


template<class Tpl>void AddData(CClient& c, CArray<Tpl>& ar)
{
 c.SetName("Fred"),    c.SetGender('m'),  c.SetAge(56),  ar.AddNew(c);
 c.SetName("Elsie"),   c.SetGender('f'),  c.SetAge(55),  ar.AddNew(c);
 c.SetName("Mark"),    c.SetGender('m'),  c.SetAge(60),  ar.AddNew(c);
 c.SetName("Joanne"),  c.SetGender('f'),  c.SetAge(59),  ar.AddNew(c);
 c.SetName("Alice"),   c.SetGender('f'),  c.SetAge(61),  ar.AddNew(c);
 c.SetName("John"),    c.SetGender('m'),  c.SetAge(62);  ar.AddNew(c);
}


int main(void)
{
 CArray<CClient> Folks;
 CClient c;

 AddData(c, Folks);
 Folks.dump();
 getchar();

 return 0;
}

The problem with this is the MAX_SIZE #define at the top. That should really be the second parameter to the template, right? In other words, the template declaration should be this…

template<class Tpl, unsigned int iSize> class CArray //CArray

All my various C++ books show something like this in describing templates and making a generic array container class. The template declaration should contain the desired maximum size of the array of whatevers. However, I can no how and no way no matter what I do figure out how to modify this program to pass this CArray object to the AddData() function if I include that 2nd unsigned int iSize parameter as part of the template definition. I’ll post below the closest that I’ve been able to come to getting this to work. Here is the modified program with the added iSize parameter in the template…

#include <afx.h>      //template7
#include <stdio.h>
#define  MAX_SIZE 10


class CClient          //CClients
{
 public:
 CClient():m_Name("xxx"),m_Sex('x'),m_Age(0){/*puts("Constructor Called!\n");*/}
 ~CClient(){/*printf("Destructor Called!\n");*/}
 void SetName(CString s)     {this->m_Name=s;}
 void SetGender(char gender) {this->m_Sex=gender;}
 void SetAge(int iAge)       {this->m_Age=iAge;}

 void input()
 {
  char name[20];
  char gender[2];
  int age;
  
  scanf("%s%s%d",name,gender,&age);
  this->m_Name=name;
  this->m_Sex=gender[0];
  this->m_Age=age;
 }

 void display(unsigned int ctr) const
 {
  CString s;

  if(this)
  {
     s.Format("%u\t%-10s\t%c\t%d\n",ctr,m_Name,m_Sex,m_Age);
     printf("%s",s);
  }
  else
  {
   s.Format("%s\t%s\t%s\t%s\n","Null","Null","Null","Null");
   printf("%s",s);
  }
 }

 private:
 CString m_Name;
 char    m_Sex;
 int     m_Age;
};


template<class Tpl, unsigned int iSize> class CArray  //CArray
{
 public:
 CArray() {puts("CArray() Constructor Called!\n");this->m_New=0;}
 ~CArray(){puts("~CArray() Destructor Called!");}

 bool AddNew(Tpl& pObj)
 {
  if(this->m_New<iSize)
  {
     x[m_New]=pObj;
     this->m_New++;
     return true;
  }

  return false;
 }

 unsigned int get_size() const
 {
  return this->m_New;
 }

 void dump()
 {
  unsigned int i;
  for(i=0;i<this->get_size();i++)
      x[i].display(i);
 }

 private:
 unsigned int  m_New;
 Tpl x[iSize];
};


template<class Tpl, unsigned int iSize>
void AddData(CClient& c, CArray<Tpl,MAX_SIZE>& ar)
{
 c.SetName("Fred"),    c.SetGender('m'),  c.SetAge(56),  ar.AddNew(c);
 c.SetName("Elsie"),   c.SetGender('f'),  c.SetAge(55),  ar.AddNew(c);
 c.SetName("Mark"),    c.SetGender('m'),  c.SetAge(60),  ar.AddNew(c);
 c.SetName("Joanne"),  c.SetGender('f'),  c.SetAge(59),  ar.AddNew(c);
 c.SetName("Alice"),   c.SetGender('f'),  c.SetAge(61),  ar.AddNew(c);
 c.SetName("John"),    c.SetGender('m'),  c.SetAge(62);  ar.AddNew(c);
}


int main(void)
{
 CArray<CClient,MAX_SIZE> Folks;
 CClient c;

 AddData(c, Folks);
 Folks.dump();
 getchar();

 return 0;
}

/*               here is this particular error.  As I vary stuff I get
                 all kinds of different errors
Compiling...
Main.cpp
C:\CODE\VSTUDIO\VC++6\PROJECTS\Templates\template6\Main.cpp(103) : error C2783: 
'void __cdecl AddData(class CClient &,class CArray<Tpl,10> &)' : 
could not deduce template argument for 'iSize'
Error executing cl.exe.

Main.obj - 1 error(s), 0 warning(s)
*/

Could someone that knows what they are doing and understands templates show me how to do this? I’m sure its something stupid on my part, but I really don’t understand templates all that well yet. I find them confusing. I wanted to tackle Atl next, but figured I ought to have a pretty good grasp of templates before tackling that.

>template<class Tpl, unsigned int iSize>
>void AddData(CClient& c, CArray<Tpl,MAX_SIZE>& ar)
Change MAX_SIZE to iSize. Since you didn't have iSize anywhere in the parameter list or as an explicit list in the instantiation, your compiler couldn't figure out what it was supposed to be.

commented: helped big time! +1

Thanks Narue! That did it. I really appreciate your taking the time to figure out my rather longish post. Now I have a few working examples of templates in use that I can study. I discovered I didn't understand the syntax for passing template classes as reference parameters when I attempted to do it.

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.