你如何在课堂上声明一个泛型类的朋友?

eve*_*992 3 c++ generics templates friend

下面的代码可以正常工作,但我想将ostream&operator <<移到类declearation之外,就像我使用hash :: operator []一样.

#include<iostream>
#include<map>

using namespace std;

template <class T>
class hash {
  private:
    map<string, T> _map;
  public:
    T& operator[] (string x);
    friend ostream& operator<<(ostream& out, const hash<T> &rhs) { return out << "test"; }
};

template <class T>
T & hash<T>::operator[](string x) {
  return _map[x];
}

int main () {
  hash<int> myobject;
  myobject["a"] = 1;
  cout << myobject["a"] << endl;
  cout << myobject << endl;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我试过了:

template <class T>
ostream& operator<<(...) {
  return out << "test";
}
Run Code Online (Sandbox Code Playgroud)

ostream& operator<<(...) {
  return out << "test";
}
Run Code Online (Sandbox Code Playgroud)

以及其他一些组合无济于事.

Dav*_*eas 6

由于这个问题似乎并未完全复制,我将解释您的程序的作用.

template <typename T>
class test {
   int private_field;
   friend std::ostream& operator<<( std::ostream&, test<T> const & );
};
// ???
int main() {
   std::cout << test<int>() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

模板按需实例化(除非您明确实例化它们),这意味着在此特定程序中test仅实例化为test<int>.当编译器实例化模板时(因为它被请求main),它将处理模板定义.此时,行为类似于在定义时使用替换类型重写代码(在此情况下恰好在此之前main):

class test<int> {
   friend std::ostream& operator<<( std::ostream&, test<int> const & );
};
Run Code Online (Sandbox Code Playgroud)

现在,如果您查看实例化模板,您可以注意到friend声明与非模板化函数成为友好关系.因此,在这个特定的程序中,您可以???使用该特定函数填写:

std::ostream& operator<<( std::ostream& o, test<int> const & t ) {
   return o << t.private_field;
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是这不容易扩展.的该代码operator<<都是相同的test<int>比对test<double>,所以应该没有必要重写相同的功能适用于所有类型的实例!

此时有两个选项,第一个是,正如您已经确定的那样,在类中提供函数的定义.然后,只要实例化类型,编译器就会处理并定义函数.这个解决方案根据需要为每个模板实例化创建非模板化函数(这是我会做的选项,即使这里有查询的奇怪和奇怪).

现在,如果您真的想避免在模板类中提供定义,并且您仍希望提供单个实现,那么您必须使用提供模板operator<<.此时您有两个不同的选项,您可以声明模板的所有实例化(我不太喜欢,因为它打开了太多其他实例),或者您可以与模板功能的单一专业化(关于访问的清洁) ,写起来比较麻烦).

第一种情况是:

template <typename T>
class test {
   template <typename U>
   friend std::ostream& operator<<( std::ostream&, test<U> const & );
};
template <typename T>
std::ostream& operator<<( std::ostream&, test<T> const & ) { ... }
Run Code Online (Sandbox Code Playgroud)

第二种情况需要几个前瞻性声明:

template <typename T> test;
template <typename T> std::ostream& operator<<( std::ostream&, test<T> const & );
template <typename T>
class test {
   friend std::ostream& operator<< <T>( std::ostream&, const test<T>& );
};
template <typename T>
std::ostream& operator<<( std::ostream&, test<T> const & ) { ... }
Run Code Online (Sandbox Code Playgroud)

当然还有另一种选择:根本不申报friend.print(std::ostream&)在类中提供具有实现的公共函数,并提供operator<<print在第二个参数上调用的非模板化函数.