I've recently learned that there are two ways to declare a template friend class or function. For example, to declare a template friend class, you may do this
template <typename T>
class goo
{
template <typename T>
friend class foo;
};
or this
template <typename T>
class goo
{
friend class foo <T>;
};
These two declarations are in fact different. The former allows you to use any type of template friend class foo with any type of template friend class goo. Where as the latter only allows you to use the same type such that you may do foo<int>
with goo<int>
but not foo<int>
with goo<char>
.
In the header file below, I try to use the latter form of the declaration to make my template friend function friend std::ostream& operator<<(std::ostream&, const Array<T>&);
more type-specific in an effort to make my program more encapsulated.
#include <iostream> #include "Animal.h" const int DefaultSize = 3; template <typename T> // declare the template and the paramenter class Array // the class being parameterized { public: Array(int itsSize = DefaultSize); Array(const Array &rhs); ~Array() { delete[] pType; } // operators Array& operator=(const Array&); T& operator[](int offSet) { return pType[offSet]; } const T& operator[](int offSet) const { return pType[offSet]; } // accessors int GetSize() const { return itsSize; } // friend function friend std::ostream& operator<< <T>(std::ostream&, const Array<T>&); private: T *pType; int itsSize; }; template <typename T> Array<T>::Array(int size = DefaultSize) :itsSize(size) { pType = new T[size]; for (int i = 0; i < size; i++) pType[i] = static_cast<T>(0); } Array<Animal>::Array(int AnimalArraySize) :itsSize(AnimalArraySize) { pType = new Animal[AnimalArraySize]; } template <typename T> Array<T>::Array(const Array &rhs) { itsSize = rhs.GetSzie(); pType = new T[itsSize]; for (int i = 0; i < itsSize; i++) pType[i] = rhs[i]; } template <typename T> Array<T>& Array<T>::operator=(const Array &rhs) { if (this == &rhs) return *this; delete[] pType; itsSize = rhs.GetSize(); pType = new T[itsSize]; for (int i = 0; i < itsSize; i++) pType[i] = rhs[i]; return *this; } template <typename T> std::ostream& operator<<(std::ostream& output, const Array<T> &theArray) { for (int i = 0; i < theArray.GetSize(); i++) output << "[" << i << "]" << theArray[i] << std::endl; return output; } #endif
However, I receive a compiler error "error C2143: syntax error : missing ';' before '<'" for line 23 which is friend std::ostream& operator<< <T>(std::ostream&, const Array<T>&);
.
When using the former form of the declaration by changing line 23 to this
template <typename T>
friend std::ostream& operator<<(std::ostream&, const Array<T>&);
My program executes without any errors.
I assume I cannot use the same syntax from type-specific template friend classes for type-specific template friend functions, or that I may be missing some kind of forward declaration. I've searched through stack-overflow and the closest topic I could find for this problem is here, but they only discuss type-specific template friend classes. I am unable to find a topic that discusses the correct syntax for using a template friend function in this way.
If this is a syntax error, what is the correct way to declare my type-specific template friend function? If this is not a syntax error, why will my program not compile?
Here are the rest of my project files for your reference. The desired behavior of my program is to show how a parametrized array uses a template to create multiple instances of different array types.
#ifndef ANIMAL_H #define ANIMAL_H #include <iostream> class Animal { public: // constructors Animal(); Animal(int); ~Animal(); // accessors int GetWeight() const { return itsWeight; } void SetWeight(int theWeight) { itsWeight = theWeight; } // friend operators friend std::ostream& operator<<(std::ostream&, const Animal&); private: int itsWeight; }; #endif
#include "Animal.h" #include <iostream> Animal::Animal() :itsWeight(0) { std::cout << "animal() "; } Animal::Animal(int weight) : itsWeight(weight) { std::cout << "animal(int) "; } Animal::~Animal() { std::cout << "Destroyed an animal..."; } std::ostream& operator<<(std::ostream& theStream, const Animal& theAnimal) { theStream << theAnimal.GetWeight(); return theStream; }
#include <iostream> #include "Animal.h" #include "Array.h" void IntFillFunction(Array<int>& theArray); void AnimalFillFunction(Array<Animal>& theArray); int main() { Array<int> intArray; Array<Animal> animalArray; IntFillFunction(intArray); AnimalFillFunction(animalArray); std::cout << "intArray...\n" << intArray; std::cout << "\nanimalArray...\n" << animalArray << std::endl; std::cin.get(); return 0; } void IntFillFunction(Array<int>& theArray) { bool Stop = false; int offset, value; while (!Stop) { std::cout << "Enter an offset (0-9) and a value. "; std::cout << "(-1 to stop): "; std::cin >> offset >> value; if (offset < 0) break; if (offset > 9) { std::cout << "***Please use values between 0 and 9.***\n"; continue; } theArray[offset] = value; } } void AnimalFillFunction(Array<Animal>& theArray) { Animal *pAnimal; for (int i = 0; i < theArray.GetSize(); i++) { pAnimal = new Animal(i * 10); theArray[i] = *pAnimal; delete pAnimal; } }
You need a forward declaration of the function template (just as you need with a class template) in order to friend a specialization. Your code should be:
template <typename T>
std::ostream& operator<<(std::ostream& output, const Array<T> &theArray);
template <typename T>
class Animal
{
// ...
friend std::ostream& operator<< <T>(std::ostream&, const Array<T>&);
};