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

这两个方法在二叉树的类中:

声明:

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类:

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

所以我重载了运营商&quot;&lt;&lt;&lt;&quot;要使用的BinaryTree类:cout&lt;&lt;树和流f&lt;&lt;树,但我收到下一条错误消息:未定义引用`operator&lt;&lt;(std :: basic_ostream&gt;&amp;,BinaryTree&amp;)'

P.S。树存储Word对象(带有int的字符串)。

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

编辑:saveToFile()中的树被声明:BinaryTree&lt; Word&gt;树。

有帮助吗?

解决方案

问题是编译器没有尝试使用您提供的模板化运算符&lt;&lt; ,而是使用非模板化版本。

当您在类中声明一个朋友时,您将在封闭范围内注入该函数的声明。下面的代码具有声明(而不是定义)一个自由函数的效果,该函数通过常量引用获取 non_template_test 参数:

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

模板类也是如此,即使在这种情况下它也不那么直观。当您在模板类主体中声明(而不是定义)友元函数时,您将声明具有该确切参数的自由函数。请注意,您要声明一个函数,而不是模板函数:

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

声明了这些自由函数但未定义。这里棘手的部分是那些自由函数不是模板,而是声明了常规自由函数。将模板函数添加到混合中时,您会得到:

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 ,并声明自由函数 void f(template_test&lt; int&gt; const&amp; amp; amp; ;),不是模板化的。当它找到调用 f(t1)时,有两个匹配的 f 符号:非模板 f(template_test&lt; int&gt; const&amp;) template_test 时声明(和未定义)的代码>在 1 声明和定义的模板化版本。非模板化版本优先,编译器匹配它。

当链接器尝试解析 f 的非模板化版本时,它找不到符号,因此失败。

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

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

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

这具有根据需要创建尽可能多的非模板化自由函数的效果。当编译器在模板 test 中找到friend声明时,它不仅会找到声明,还会找到实现,并将两者都添加到封闭范围。

将模板版本设为朋友

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

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 模板。朋友声明被修改为包括尖括号,用于标识我们正在制作朋友的元素实际上是模板而不是自由函数。

回到问题

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

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

使用该代码,您强制编译器为每个实例化类型生成非模板化运算符&lt;&lt; ,并且生成的函数委托 dump 方法模板。

其他提示

你不需要模板操作符声明,你必须声明操作符“friend”让您的类授予其他类的访问权限,在本例中为std :: cout

friend std::ostream& operator << ( std::ostream& os, BinaryTree & tree )
{
    doStuff( os, tree );
    return os;
}

推荐阅读: http://www.parashift.com/c++- FAQ-精简版/ friends.html

当重载&lt;&lt;&lt; 运算符时,你想使用const引用:

template <class T>
std::ostream& operator << (std::ostream& os, const BinaryTree<T>& tree) 
{
    // output member variables here... (you may need to make
    // this a friend function if you want to access private
    // member variables...

    return os;
}

确保完整的模板定义(而不仅仅是原型)在include(即.h,.hpp)文件中作为模板,并且单独的编译不能一起工作。

我不知道@Dribeas正在使用什么链接器,但这肯定会导致GNU链接器给出未定义的引用错误。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top