简体   繁体   English

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

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

The following code works, but i would like to move ostream& operator<< outside of the class declearation as i have with hash::operator[]. 下面的代码可以正常工作,但我想将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;
}

I have tried: 我努力了:

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

and

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

as well as a few other combinations to no avail. 以及其他一些组合无济于事。

Since it does not seem that this question is getting closed as exact duplicate, I will explain what your program does. 由于这个问题似乎并未完全复制,我将解释您的程序的作用。

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

Templates are instantiated on demand (unless you explicitly instantiate them), that means that in this particular program test is instantiated only as test<int> . 模板按需实例化(除非您显式实例化它们),这意味着在此特定程序中, test仅作为test<int>实例化。 When the compiler instantiates the template (because it was requested in main ) it will process the template definition. 当编译器实例化模板时(因为它是在main中请求的),它将处理模板定义。 At this point the behavior is similar to rewriting the code with the substituted type at the point of definition (in this case right before main ): 此时,行为类似于在定义时使用替换类型重写代码(在这种情况下恰好在main之前):

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

Now, if you look at the instantiated template, you can note that the friend declaration is befriending a non templated function. 现在,如果你查看实例化的模板,你可以注意到friend声明是一个非模板化函数。 So in this particular program you can fill in the ??? 所以在这个特定的程序中你可以填写??? with that particular function: 具有该特定功能:

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

The problem here is that this is not easily extensible. 这里的问题是这不容易扩展。 The code of that operator<< is the same for test<int> than it is for test<double> , so there should be no need to rewrite the same function for all instantiating types! 对于test<int> ,该operator<<的代码与test<double>的代码相同,因此不需要为所有实例化类型重写相同的函数!

At this point there are two options, the first one is, as you have already identified, providing the definition of the function inside the class. 此时有两个选项,第一个是,正如您已经确定的那样,在类中提供函数的定义。 The compiler will then process and define the function whenever the type is being instantiated. 然后,只要实例化类型,编译器就会处理并定义函数。 This solution creates non-templated functions on demand for each template instantiation (which is the option I would do, even with the quirks and strangeness of lookup here). 这个解决方案根据需要为每个模板实例化创建非模板化函数(这是我会做的选项,即使这里有查询的奇怪和奇怪)。

Now, if you really want to avoid providing the definition inside the templates class, and you still want to provide a single implementation, then you have to resort to providing a templates operator<< . 现在,如果您真的想避免在模板类中提供定义,并且您仍然希望提供单个实现,那么您必须使用模板operator<< At this point you have two different options, you can declare all instantiations of the template (which I don't quite like, as it opens to too many others), or you can befriend a single specialization of the template function (cleaner regarding access, more cumbersome to write). 此时您有两个不同的选项,您可以声明模板的所有实例化(我不太喜欢,因为它打开了太多其他实例),或者您可以与模板功能的单一专业化(关于访问的清洁) ,写起来比较麻烦)。

The first case is: 第一种情况是:

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 & ) { ... }

The second case requires a couple of forward declarations: 第二种情况需要几个前瞻性声明:

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 & ) { ... }

There is of course another option: do not declare friend s at all. 当然还有另一种选择:根本不要申报friend Provide a print(std::ostream&) public function in your class that has the implementation, and provide a non-templated operator<< that just calls print on the second argument. 在类中提供具有实现的print(std::ostream&)公共函数,并提供一个非模板化的operator<<只调用第二个参数的print

You have to be careful when you use friend and template 使用朋友模板时必须小心

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

you need to use a different template U because operator<< is a friend method (external), if we use T instead of U , we will have : ambiguous definition in template . 你需要使用不同的模板U,因为operator <<朋友方法(外部),如果我们使用T而不是U ,我们将在模板中有: 模糊定义

Change hash by MyHash to avoid ambiguities. 通过MyHash更改哈希以避免歧义。

Edit : 编辑:

The error that you get here is : 你在这里得到的错误是:

error C2676: '<' binaire : 'std::string' ne définit pas cet opérateur ou une conversion vers un type acceptable pour l'opérateur prédéfini 错误C2676:'<'binaire:'std ::string'neéfinitpascetopérateurouune conversion vers un type acceptable pour l'opérateurprédéfini

because you forgot to include <string> in "hash.h" . 因为你忘了在“hash.h”中包含<string> That header defines the < operator . 该标题定义了<运算符

And also try moving the definition of operator[] and operator<< directly into "hash.h" Both the declaration and definition of templates must be included. 并且还尝试将operator []operator <<的定义直接移动到“hash.h”中 。必须包含模板的声明和定义。 This is because in some compilers template functions cannot be compiled and linked independently, since they are generated on request for the specific types they are instantiated with. 这是因为在某些编译器中,模板函数无法独立编译和链接,因为它们是在对实例化的特定类型的请求时生成的。

Change the #include "hash.cpp" to #include "hash.h" #include“hash.cpp”更改为#include“hash.h”

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

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