重载操作符<<为模板类 [英] Overloading operator<< for a templated class

查看:129
本文介绍了重载操作符<<为模板类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图实现一个返回流的二叉树的方法。我想使用方法中返回的流在屏幕中显示树或将树保存在文件中:

I'm trying to implement a method for a binary tree which returns a stream. I want to use the stream returned in a method to show the tree in the screen or to save the tree in a file:

这两个方法都在二叉树:

These two methods are in the class of the binary tree:

声明:

void streamIND(ostream&,const BinaryTree<T>*);
friend ostream& operator<<(ostream&,const BinaryTree<T>&);

template <class T>
ostream& operator<<(ostream& os,const BinaryTree<T>& tree) {
    streamIND(os,tree.root);
    return os;
}

template <class T>
void streamIND(ostream& os,Node<T> *nb) {
    if (!nb) return;
    if (nb->getLeft()) streamIND(nb->getLeft());
    os << nb->getValue() << " ";
    if (nb->getRight()) streamIND(nb->getRight());
}

此方法在UsingTree类中:

This method is in UsingTree class:

void UsingTree::saveToFile(char* file = "table") {
    ofstream f;
    f.open(file,ios::out);
    f << tree;
    f.close();
}



因此我重载了运算符<的BinaryTree类使用:cout<树和流f'树,但我收到下一个错误消息:未定义引用`operator< <(std :: basic_ostream>& BinaryTree&)'

So I overloaded the operator "<<" of the BinaryTree class to use: cout << tree and ofstream f << tree, but I receive the next error message: undefined reference to `operator<<(std::basic_ostream >&, BinaryTree&)'

树存储Word对象(一个带有int的字符串)。

P.S. The tree stores Word objects (a string with an int).

我希望你能理解我可怜的英语。谢谢!
我想为STL的初学者了解一个好的文本,解释所有必要的,因为我浪费我所有的时间在这样的错误。

I hope you understand my poor English. Thank you! And I'd like to know a good text for beginners about STL which explains all necessary because i waste all my time in errors like this.

编辑:在saveToFile()中的树被声明:BinaryTree< Word>树。

tree in saveToFile() is declared: BinaryTree< Word > tree.

推荐答案

问题是编译器不试图使用模板

The problem is that the compiler is not trying to use the templated operator<< you provided, but rather a non-templated version.

当你在类中声明一个朋友时,你正在注入一个类的声明函数。以下代码具有声明(而不是定义)通过常量引用获取非_template_test参数的自由函数的效果:

When you declare a friend inside a class you are injecting the declaration of that function in the enclosing scope. The following code has the effect of declaring (and not defining) a free function that takes a non_template_test argument by constant reference:

class non_template_test
{
   friend void f( non_template_test const & );
};
// declares here:
// void f( non_template_test const & );

模板类也是如此,即使在这种情况下,它不太直观。当你在模板类体中声明(而不是定义)一个friend函数时,你正在声明一个带有完全参数的自由函数。注意,您要声明一个函数,而不是一个模板函数:

The same happens with template classes, even if in this case it is a little less intuitive. When you declare (and not define) a friend function within the template class body, you are declaring a free function with that exact arguments. Note that you are declaring a function, not a template function:

template<typename T>
class template_test
{
    friend void f( template_test<T> const & t );
};
// for each instantiating type T (int, double...) declares:
// void f( template_test<int> const & );
// void f( template_test<double> const & );

int main() {
    template_test<int> t1;
    template_test<double> t2;
}

这些自由函数声明但未定义。这里棘手的部分是那些自由函数不是一个模板,而是定期的自由函数被声明。当你添加模板函数到混合中你得到:

Those free functions are declared but not defined. The tricky part here is that those free functions are not a template, but regular free functions being declared. When you add the template function into the mix you get:

template<typename T> class template_test {
   friend void f( template_test<T> const & );
};
// when instantiated with int, implicitly declares:
// void f( template_test<int> const & );

template <typename T>
void f( template_test<T> const & x ) {} // 1

int main() {
   template_test<int> t1;
   f( t1 );
}

当编译器命中main函数时,它实例化模板 template_test< int> const&)< / c ++ c>中的类型 int code>不是模板。当它找到调用 f(t1)时,有两个匹配的 f 符号:非模板<$ c当 template_test 被实例化时,$ c> f(template_test< int> const&) 1 下声明和定义。

When the compiler hits the main function it instantiates the template template_test with type int and that declares the free function void f( template_test<int> const & ) that is not templated. When it finds the call f( t1 ) there are two f symbols that match: the non-template f( template_test<int> const & ) declared (and not defined) when template_test was instantiated and the templated version that is both declared and defined at 1. The non-templated version takes precedence and the compiler matches it.

当链接器尝试解析 f 它找不到符号,因此失败。

When the linker tries to resolve the non-templated version of f it cannot find the symbol and it thus fails.

我们能做什么?有两种不同的解决方案。在第一种情况下,我们使编译器为每个实例化类型提供非模板化函数。在第二种情况下,我们将模板版本声明为朋友。

What can we do? There are two different solutions. In the first case we make the compiler provide non-templated functions for each instantiating type. In the second case we declare the templated version as a friend. They are subtly different, but in most cases equivalent.

让编译器为我们生成非模板函数:

template <typename T>
class test 
{
   friend void f( test<T> const & ) {}
};
// implicitly

这样做的效果是创建尽可能多的非模板化自由函数需要。当编译器在模板 test 中找到朋友声明时,它不仅找到声明,还找到了实现,并将两者添加到包围范围。

This has the effect of creating as many non-templated free functions as needed. When the compiler finds the friend declaration within the template test it not only finds the declaration but also the implementation and adds both to the enclosing scope.

使模板版本成为朋友

为了使模板成为朋友,我们必须声明它,并告诉编译器,我们想要的朋友实际上是一个模板而不是一个非模板的自由函数:

To make the template a friend we must have it already declared and tell the compiler that the friend we want is actually a template and not a non-templated free function:

template <typename T> class test; // forward declare the template class
template <typename T> void f( test<T> const& ); // forward declare the template
template <typename T>
class test {
   friend void f<>( test<T> const& ); // declare f<T>( test<T> const &) a friend
};
template <typename T> 
void f( test<T> const & ) {}

在声明 f 作为模板之前,我们必须转发声明模板。要声明 f 模板,我们必须先声明 test 模板。朋友声明被修改为包括尖括号,其表示我们正在做朋友的元素实际上是模板而不是自由函数。

In this case, prior to declaring f as a template we must forward declare the template. To declare the f template we must first forward declare the test template. The friend declaration is modified to include the angle brackets that identify that the element we are making a friend is actually a template and not a free function.

返回问题

回到你的特定例子,最简单的解决方案是让编译器通过内联友元函数的声明来生成函数: / p>

Going back to your particular example, the simplest solution is having the compiler generate the functions for you by inlining the declaration of the friend function:

template <typename T>
class BinaryTree {
   friend std::ostream& operator<<( std::ostream& o, BinaryTree const & t ) {
      t.dump(o);
      return o;
   }
   void dump( std::ostream& o ) const;
};

使用该代码,您迫使编译器生成一个非模板化的 ; 为每个实例化类型,并且生成的函数委托模板的 dump 方法。

With that code you are forcing the compiler into generating a non-templated operator<< for each instantiated type, and that generated function delegates on the dump method of the template.

这篇关于重载操作符&lt;&lt;为模板类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆