如何在类声明之外声明泛型类的朋友?

时间:2012-03-17 23:11:02

标签: c++ templates generics friend

以下代码有效,但我想移动ostream&运营商LT;<除了我在hash :: operator []。

之外的类declearation
#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;
}

我试过了:

template <class T>
ostream& operator<<(...) {
  return out << "test";
}

ostream& operator<<(...) {
  return out << "test";
}

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

2 个答案:

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

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

class test<int> {
   friend std::ostream& operator<<( std::ostream&, test<int> const & );
};

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

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

这里的问题是这不容易扩展。 operator<<的{​​{1}}代码与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 & ) { ... }

当然还有另一种选择:根本不要声明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 & ) { ... } 。在您的类中提供具有实现的friend公共函数,并提供一个非模板print(std::ostream&),只在第二个参数上调用operator<<

答案 1 :(得分:3)

使用朋友模板

时必须小心
#include<iostream>
#include<map>

template <class T>
class MyHash{
public:
    // ... use your T template here
    template <class U>
    friend ostream& operator<<(ostream& out, const MyHash<U> &rhs);
};

// ...
template <class U>
ostream& operator<<(ostream& out, const MyHash<U> &rhs){ return out << "test"; }

您需要使用其他模板U ,因为运算符&lt;&lt; 朋友方法(外部),如果我们使用 T 而不是 U ,我们将:模板中的模糊定义

通过 MyHash 更改哈希,以避免含糊不清。

修改:

您获得的错误here是:

  

错误C2676:'&lt;' binaire:'std ::string'nedéfinitpascetopérateur   ou une转换为un type type pour l'opérateurprédéfini

因为您忘记将<string>包含在“hash.h”中。该标题定义&lt;操作即可。

并尝试将运算符[] 运算符&lt;&lt; 的定义直接移至“hash.h” 必须包含模板的声明和定义。这是因为在某些编译器中,模板函数无法独立编译和链接,因为它们是根据请求生成的特定类型生成的。

#include“hash.cpp”更改为 #include“hash.h”