如何解决以下错误?

时间:2011-03-07 11:33:57

标签: c++

每当我尝试在VS 2010中编译以下程序errors时,我都会收到以下错误 - http://codepad.org/Bf9l8j9H

知道如何解决错误吗?

2 个答案:

答案 0 :(得分:3)

这是一个链接器错误,它表示您已声明但未定义(或定义未链接)以下重载:

std::ostream& operator<<( std::ostream&, node<weight>& );

从这里开始的常见检查是检查你是否有一个定义,定义签名是否与声明匹配(你声明了,但定义了运算符采用const引用吗?),是否正在编译定义和联...

我只是花了一些时间并实际阅读了代码,我将基本上将其浓缩为:

template <typename T>
struct node {
   friend std::ostream& operator<<( std::ostream&, node<T>& ); // [1] !!!!
};
template <typename T>
std::ostream& operator<<( std::ostream& o, node<T>& n ) {} // [2]

这是一个常见的错误,也是为什么在与他们成为朋友的模板中内联友元函数的定义更简单的原因之一。基本上,在[1]中,您的模板声明(和交友)一个带有ostream&node<T>&对象的非模板化函数。

这里的细微之处在于,当模板被实例化为某个特定类型,并且friend声明被处理时,T被修复,并且该行成为一个免费的非模板化函数。例如,如果您使用node实例化int,就像node<int> n一样,编译器将注入int并用T替换friend,然后{{1}声明将是:friend ostream& operator<<( ostream&, node<int>& ),然后在封闭的命名空间中声明一个自由函数。使该声明显式化(假设您只使用int实例化模板,编译器将您的代码读取为:

template <typename T> struct node {
   friend ostream& operator<<( ostream&, node& ); // [1] note <T> not required here
};
// instantiating with int:
ostream& operator<<( ostream&, node<int>& ); // [3] declaration, not definition

template <typename T>
ostream& operator<<( ostream&, node<T>& ) {} // [2] your definition

此时,无论何时键入std::cout << a_int_node;,编译器都会考虑所有重载,它会找到一个非模板化的自由函数[3],它是一个完美匹配,一个模板化版本[2],但是非模板化版本优先。编译器不会实例化模板operator<<,并期望您在一个翻译单元中手动定义函数。

<强>解决方案

最简单的最佳解决方案是让编译器为您生成免费功能。你可以在模板化的类中提供操作符定义,一切都会很简单:

template <typename T>
struct node {
   friend std::ostream& operator<<( std::ostream& o, node& n ) // [1]
   { /* code goes here */ return o; }
};

即使代码在模板内部,由于friend存在,您实际上是在命名空间级别声明和定义函数。如果使用int实例化模板,编译器将在封闭的命名空间中为您生成:std::ostream& operator<<( std::ostream&, node<int>& )

此解决方案是世界上最好的解决方案:您只授予对单段代码的访问权限,并且编译器会处理大部分血腥细节。

另一方面,您可以与整个模板功能成为朋友。其语法如下:

template <typename T>
struct node {
   template <typename U>
   friend std::ostream& operator<<( std::ostream&, node<U>& ); // [4]
};
template <typename T>
std::ostream& operator<<( std::ostream& o, node<T>& n )  // can access private parts
{ /* code goes here */ return o; }

在这种情况下,您将向模板化函数的所有实例化打开node的所有实例化,这在语义上将该类打开给其他用户。

第三个选项是与单个模板实例化建立联系,这与第一个选项具有相同的效果,唯一的区别在于您使用模板化的自由函数而不是非模板化的自由函数。另一方面,语法非常麻烦,因为它需要在成为友好之前声明函数模板,而这反过来需要声明类模板:

template <typename T> struct node;                   // forward declare the class template
template <typename T>
std::ostream& operator<<( std::ostream&, node<T>& ); // declare function template
template <typename T>
struct node {                                        // define class template
   friend std::ostream& operator<< <>( std::ostream&, node<T>& ); // befriend instantiation
};
template <typename T>
std::ostream& operator<<( std::ostream& o, node<T>& n ) // define function template
{ ... }

如您所见,最简单的最佳解决方案是在类定义中定义函数模板。

答案 1 :(得分:0)

conio.h是MS-DOS编译器的旧标题;更新:它仍然可以在VS 2010中使用。

最好是使用它后声明的流。