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

时间:2015-04-07 22:34:54

标签: c++ templates syntax compiler-errors friend-function

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

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

或者

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

这两个声明实际上是不同的。前者允许您使用任何类型的模板朋友类foo与任何类型的模板朋友类goo。后者只允许您使用相同的类型,以便foo<int> goo<int> foo<int>goo<char>friend std::ostream& operator<<(std::ostream&, const Array<T>&);

在下面的头文件中,我尝试使用后一种形式的声明来使我的模板友好函数#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 更具特定类型,以使我的程序更加封装。

// ARRAY_H

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

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

通过将第23行更改为此

来使用前一种形式的声明
#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

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

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

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

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

// ANIMAL_H

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

// ANIMAL.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;
  }
}

// Main.cpp的

{{1}}

2 个答案:

答案 0 :(得分: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);
    //...
};

答案 1 :(得分:0)

您需要功能模板的前向声明(就像您需要使用类模板一样)才能成为专业化的朋友。你的代码应该是:

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