Frustration with first foray into template classes.

I am a newb to C++'s template class mechanism and am having problems with something probably has a solution that will make me feel stupid. Oh well.

So I have this class...

1
2
3
4
5
6
7
8
9
10
// party.h
template <class T>
class Party
{ // doubly-linked list of Actors; Actor has children Ally and Foe
  public:
    Party<T>() ; // default constructor; defaults initial size 
    Party<T>( unsigned short ms ) ; // Allows size specification.
    // etc.
  // etc.
};


...and I'm trying to instantiate it thusly...

1
2
// main.cpp... line 60 below
Party<Ally> *party = new Party<Ally>(3) ;


I get this back from g++:
main.o: In function `main':
main.cpp:(.text+0x1106): undefined reference to `Party<Ally>::Party(unsigned short)'


I had read in the advanced tutorials regarding templates that you can't separate a template class's prototype into a header file, so I moved it to the .cpp file, rebuilt, and was greeted with this error instead:

main.cpp: In function `main(int, char**)':
main.cpp:60: error: invalid use of undefined type 'struct Party<Ally>'
party.h:41: error: declaration of 'struct Party<Ally>'


Wait, huh? struct?

 
template <class T> class Party ; // the line in question 


Sigh.

The whole point of making Party a templatized class is that the two polymorphic children of Actor -- namely, Ally and Foe -- will have some methods that are not merely specialized, but unique. For example, there is an Ally::reroll() but not a Foe::reroll(), and there are lots of UI functions for Ally that, logically, wouldn't exist for Foe. I could just create Party as a doubly-linked list of Actor objects, but then to use anything that's defined only in one of the children, I'd have to constantly cast the party member:

1
2
(Ally(party[i]))->manageEquipment() ; // because there's no Actor::manageEquipment().
// ...and yes I defined a [] operator to fetch the Nth Actor in the list. 


I'd rather create Party objects and then define upfront whether the objects coming out of it are of type Ally or Foe.

So I guess I really have two questions:
* How do I get the instantiation of Party<Ally> to work?
* Should I give up, un-templatize Party, and have it simply contain Actors that can be type-casted when needed?

Pleh?
You cannot split template declarations and definitions.
The definition must be visible from where the template class is used so the compiler can create an instantiation for the desired template parameters.
If you're trying to write party[i]->manageEquipment(); and have it call Ally::manageEquipment, your options are:

1) Party holds a container of pointers to Ally or to Ally's base class, whose public interface includes manageEquipment(). Based on your description, Actor is not suitable.

2) Party<T> holds a container of pointers to T (or, better of T)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <vector>

struct Ally { void manageEquipment() {} };
struct Foe {};

template<typename T>
class Party
{
    std::vector<T> data;
 public:
    Party(std::size_t sz) : data(sz) {}
    T& operator[](std::size_t n) { return data[n]; }
    T operator[](std::size_t n) const { return data[n]; }
}
int main()
{
    Party<Ally> party1(10);
    party1[2].manageEquipment();

    Party<Foe> party2(10);
    party2[2].manageEquipment(); // compile-time error
}



Topic archived. No new replies allowed.