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

Wan*_*ool 0 c++ syntax templates compiler-errors friend-function

我最近了解到有两种方法可以声明模板友元类或函数.例如,要声明模板好友类,您可以执行此操作

template <typename T>
class goo
{
    template <typename T>
    friend class foo;
};
Run Code Online (Sandbox Code Playgroud)

或这个

template <typename T>
class goo
{
    friend class foo <T>;
};
Run Code Online (Sandbox Code Playgroud)

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

在下面的头文件中,我尝试使用后一种形式的声明来使我的模板友元函数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
Run Code Online (Sandbox Code Playgroud)

但是,我收到编译器错误"错误C2143:语法错误:缺少';' 在第23行的'<'之前friend std::ostream& operator<< <T>(std::ostream&, const Array<T>&);.

通过将第23行更改为此来使用前一种形式的声明

template <typename T>
friend std::ostream& operator<<(std::ostream&, const Array<T>&);
Run Code Online (Sandbox Code Playgroud)

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

我假设我不能使用特定于类型的模板友元类的相同语法来处理特定于类型的模板友元函数,或者我可能缺少某种前向声明.我已经通过堆栈溢出搜查,我能找到这个问题的最近的话题是在这里,但他们只讨论特定类型的模板友元类.我无法找到讨论以这种方式使用模板友元函数的正确语法的主题.

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

以下是我的项目文件的其余部分供您参考.我的程序所需的行为是显示参数化数组如何使用模板创建不同数组类型的多个实例.

// 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
Run Code Online (Sandbox Code Playgroud)

//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;
}
Run Code Online (Sandbox Code Playgroud)

//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;
  }
}
Run Code Online (Sandbox Code Playgroud)

asc*_*ler 5

在将专业化称为朋友之前,您需要声明函数模板.

// 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);
    //...
};
Run Code Online (Sandbox Code Playgroud)