繁体   English   中英

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

[英]How do you declare the friend of a generic class outside of the class decleration?

下面的代码可以正常工作,但我想将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;
}

我努力了:

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

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

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

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

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

这里的问题是这不容易扩展。 对于test<int> ,该operator<<的代码与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<<只调用第二个参数的print

使用朋友模板时必须小心

#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,因为operator <<朋友方法(外部),如果我们使用T而不是U ,我们将在模板中有: 模糊定义

通过MyHash更改哈希以避免歧义。

编辑:

你在这里得到的错误是:

错误C2676:'<'binaire:'std ::string'neéfinitpascetopérateurouune conversion vers un type acceptable pour l'opérateurprédéfini

因为你忘了在“hash.h”中包含<string> 该标题定义了<运算符

并且还尝试将operator []operator <<的定义直接移动到“hash.h”中 。必须包含模板的声明和定义。 这是因为在某些编译器中,模板函数无法独立编译和链接,因为它们是在对实例化的特定类型的请求时生成的。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM