如何在我的模板 class 中声明特定于类型的模板友元函数?

How do I declare a template friend function that is type-specific in my template class?

我最近了解到有两种方法可以声明模板友元 class 或函数。例如,声明一个模板朋友class,你可以这样做

template <typename T>
class goo
{
    template <typename T>
    friend class foo;
};

或这个

template <typename T>
class goo
{
    friend class foo <T>;
};

这两个声明实际上是不同的。前者允许您将任何类型的模板朋友 class foo 与任何类型的模板朋友 class goo 一起使用。因为后者只允许你使用相同的类型,所以你可以用 goo<int>foo<int> 但不能用 goo<char>.

foo<int>

在下面的头文件中,我尝试使用后一种形式的声明来使我的模板友元函数friend std::ostream& operator<<(std::ostream&, const Array<T>&);更加特定于类型,从而使我的程序更加封装。

//ARRAY_H

#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

但是,我收到第 23 行的编译器错误 "error C2143: syntax error : missing ';' before '<'",即 friend std::ostream& operator<< <T>(std::ostream&, const Array<T>&);

当通过将第 23 行更改为这种形式使用声明的前一种形式时

template <typename T>
friend std::ostream& operator<<(std::ostream&, const Array<T>&);

我的程序执行没有任何错误。

我假设我不能将特定类型模板友元 classes 中的相同语法用于特定类型模板友元函数,或者我可能缺少某种前向声明。我搜索了堆栈溢出,我能找到的最接近这个问题的主题是 here,但他们只讨论特定类型的模板朋友 classes。我找不到讨论以这种方式使用模板友元函数的正确语法的主题。

如果这是一个语法错误,那么声明特定类型模板友元函数的正确方法是什么?如果这不是语法错误,为什么我的程序无法编译?

这是我的其余项目文件,供您参考。我的程序的预期行为是展示参数化数组如何使用模板创建不同数组类型的多个实例。

//ANIMAL_H

#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

//ANIMAL.CPP

#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;
}

//MAIN.CPP

#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;
  }
}

您需要函数模板的前向声明(就像您需要 class 模板一样)以便与专业化相结合。您的代码应该是:

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>&);
};

您需要先声明函数模板,然后才能将专业化作为友元引用。

// Forward declare class template.
template <typename T> class Array;

// Declare function template.
template <typename T>
std::ostream& operator<<(std::ostream& os, const Array<T>& arr);

template <typename T>
class Array
{
    //...
    friend std::ostream& operator<< <>(
        std::ostream& os, const Array<T>& arr);
    //...
};