recurring template problem

V

velthuijsen

I've been reading (and using the examples in) Thinking in C++ (vol 2).

One of the things that the author shows you can do with templates is
the following:

#include <iostream>
using namespace std;

template<class T>
class Counted
{
static int count;
public:
Counted() { ++count; }
Counted(const Counted<T>&) { ++count; }
~Counted() { --count; }
static int getCount() { return count; }

};

template<class T>
int Counted<T>::count = 0;

// Curious class definitions
class CountedClass : public Counted<CountedClass> {};
class CountedClass2 : public Counted<CountedClass2> {};

int main()
{
CountedClass a;
cout << CountedClass::getCount() << endl; // 1
CountedClass b;
cout << CountedClass::getCount() << endl; // 2
CountedClass2 c;
cout << CountedClass2::getCount() << endl; // 1 (!)
} ///:~

I've tried adapting this idea to the following class that I've
used/created to try out some other things (Below is the almost working
example).

Header file:
Code:
#ifndef ID_CLASS_H
#define ID_CLASS_H

#include <map>

// magic number defines
#define NOT_A_VALID_ID       -1

template<class T>
class ID_Class
{
private:
static std::map<int, int>		ID_Map;
int					ID_Value;

void DecrementReference();
void IncrementReference();

public:
// Only reason to ever NOT use the default constructor is when you
read
// the IDs from a source instead of creating new IDs.
ID_Class(int tID);
ID_Class();
~ID_Class();

ID_Class(const ID_Class<T>& Right);
ID_Class<T>& operator= (const ID_Class<T>& Right);

int Get_ID() const;

// Test/debug functions below this comment
void DumpMap() const;
};

#endif

cpp:
#include "ID_Class.h"

#include <stdexcept>
#include <ostream>
// note that #include <map> has been defined in the header. This is
needed
// for the static definition used there.

using std::cout;
using std::overflow_error;
using std::bad_alloc;
using std::pair;
using std::map;

template<class T>
map<int, int> ID_Class<T>::ID_Map;

// private functions
template<class T>
void ID_Class<T>::DecrementReference()
{
map<int,int>::iterator it = ID_Map.find(ID_Value);
--(it->second);
if ( it->second < 1)
{
ID_Map.erase(it);
}
}

template<class T>
void ID_Class<T>::IncrementReference()
{
map<int,int>::iterator it = ID_Map.find(ID_Value);
++(it->second);
if (it->second < 1)
{
throw overflow_error("To many copies exist");
}
}

// public functions
template<class T>
ID_Class<T>::ID_Class(int tID)
{
ID_Value = tID;
if ((ID_Map.insert(pair<int,int>(ID_Value,1))).second == false)
{
throw bad_alloc();
}
}

template<class T>
ID_Class<T>::ID_Class()
{
ID_Value = 1;
map<int,int>::const_iterator it (ID_Map.begin());
map<int,int>::const_iterator itEnd (ID_Map.end());

while(( it != itEnd) && (ID_Value == (*it).first))
{
++ID_Value;
++it;
}
if (ID_Value < 1)
{
throw overflow_error("Requested negative ID");
}
if ((ID_Map.insert(pair<int,int>(ID_Value,1))).second == false)
{
throw bad_alloc();
}
}

template<class T>
ID_Class<T>::~ID_Class()
{
DecrementReference();
}

template<class T>
ID_Class<T>::ID_Class(const ID_Class<T>& Right)
{
ID_Value = Right.ID_Value;
IncrementReference();
}

template<class T>
ID_Class<T>& ID_Class<T>::operator= (const ID_Class<T>& Right)
{
DecrementReference();
ID_Value = Right.ID_Value;
IncrementReference();
return *this;
}

template<class T>
int ID_Class<T>::Get_ID() const
{
return ID_Value;
}

// Test/Debug functions below this comment
template<class T>
void ID_Class<T>::DumpMap() const
{
map<int,int>::const_iterator it (ID_Map.begin());
map<int,int>::const_iterator itEnd (ID_Map.end());
while (it != itEnd)
{
cout << "ID " << (*it).first << " Has " << (*it).second << " copies"
<< endl;
++it;
}
}

main.cpp:

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

using namespace std
class MainID : public ID_Class<MainID>
{
};

int main( int argc, char* argv[])
{
// MainID    TestID;

char t;
cin.get(t);
return(0);
};

I know that I'm missing something here since the code will compile
without a warning but when I uncomment // Main    TestID; I get
unresolved externals (ctor & dtor). The question is what is is that am
I missing? What rules am I trying to break? And is there a way around
the problem?
 
J

John Harrison

velthuijsen said:
I've been reading (and using the examples in) Thinking in C++ (vol 2).

One of the things that the author shows you can do with templates is
the following:
[snip]

I know that I'm missing something here since the code will compile
without a warning but when I uncomment // Main TestID; I get
unresolved externals (ctor & dtor). The question is what is is that am
I missing? What rules am I trying to break? And is there a way around
the problem?

It's the old, old problem. Put all your template code in the header file,
that's where it belongs. I'm surprised Bruce Eckel didn't explain that in
his book, but here it is in the FAQ.

http://www.parashift.com/c++-faq-lite/containers-and-templates.html

questions 34.12 to 34.15

john
 
V

velthuijsen

John Harrison said:
velthuijsen said:
I've been reading (and using the examples in) Thinking in C++ (vol 2).

One of the things that the author shows you can do with templates is
the following:
[snip]

I know that I'm missing something here since the code will compile
without a warning but when I uncomment // Main TestID; I get
unresolved externals (ctor & dtor). The question is what is is that am
I missing? What rules am I trying to break? And is there a way around
the problem?

It's the old, old problem. Put all your template code in the header file,
that's where it belongs. I'm surprised Bruce Eckel didn't explain that in
his book, but here it is in the FAQ.

He did. In his first book, chapter 16. Guess this is what I get when I
just copy/paste existing files instead of trying to remember all the
excercises he'd suggested.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,539
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top