积极答复者
为模板类重载operator<<时出的错误

问题
-
#pragma once #include <iostream> template<typename T> class B; template<typename T> std::ostream& operator<<(std::ostream &o, const B<T> &b) { o<<b.b<<std::endl; return o; } template<typename T> class B { friend std::ostream& operator<<(std::ostream &, const B<T> &); public: explicit B(int _b = 0) : b(_b) { } private: int b; };
以上是test.h文件,文件main.cpp是这样的
#include <iostream> #include "test.h" using namespace std; int main() { B<int> b(2); cout<<b; return 0; }
请问,为什么链接时会出现错误:
1>main.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class B<int> const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$B@H@@@Z) referenced in function _main
1>C:\Users\lhl\Documents\Visual Studio 2008\Projects\lhlproj\Debug\test2.exe : fatal error LNK1120: 1 unresolved externals如果友元声明是这样:
template<typename _T> friend std::ostream& operator<<(std::ostream &, const B<_T> &);
就可以链接通过。为什么?
LHL
答案
-
-
前面已经说过了,函数模板和类模板特化不是一回事。你的友元函数声明特化后成为
ostream & operator << <int> (std::ostream &, const B<int> )
而不是你前面声明的
template<T>
ostream & operator << (std::ostream &, const B<T> )
在C++里面通过模板特化的函数和没有通过模板特化的函数是不同的。例如同时声明两个函数
template<typename T> void f(T);
void f(int);
f(1)调用的是void f(int),而f<int>(1)调用的是template<typename T> void f(T);。
你应该把友元函数声明为函数模板
template<typename T1>
friend std::ostream& operator<<(std::ostream &, const B<T1> &);
The following is signature, not part of post
Please mark the post answered your question as the answer, and mark other helpful posts as helpful.
Visual C++ MVP- 已标记为答案 lhlzhxh 2010年4月14日 3:02
-
啊,太谢谢诸位的热心回答了,我现在终于明白了。
其实,我在模板类B中这样声明友元就可以了:friend std::ostream& operator<< <T> (std::ostream &, const B<T> &);
我的本意是这样的,我要限制std::ostream& operator<< <int>(std::ostream &, const B<int>&)只作为class B<int>的友元,而不能作为class B<float>的友元(不管这样做是不是有必要),也就是说类型要对应(这叫做绑定友元声明),哈哈,我参照《C++ Primer》第三版的说明声明了友元,却出了错误,现在看来那本书是有错误的,它忘记了在operator<<后面加上<T>就像其他绑定的友元函数模板一样。
版主的回复提醒了我,谢谢了。
LHL- 已标记为答案 lhlzhxh 2010年4月14日 3:21
全部回复
-
-
#pragma once #include <iostream> template<typename T> class B; template<typename T> std::ostream& operator<<(std::ostream &o, const B<T> &b) { o<<b.b<<std::endl; return o; } template<typename T> class B { friend std::ostream& operator<<(std::ostream &, const B<T> &); public: explicit B(int _b = 0) : b(_b) { } private: int b; };
以上是test.h文件,文件main.cpp是这样的
#include <iostream> #include "test.h" using namespace std; int main() { B<int> b(2); cout<<b; return 0; }
请问,为什么链接时会出现错误:
1>main.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class B<int> const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$B@H@@@Z) referenced in function _main
1>C:\Users\lhl\Documents\Visual Studio 2008\Projects\lhlproj\Debug\test2.exe : fatal error LNK1120: 1 unresolved externals如果友元声明是这样:
template<typename _T> friend std::ostream& operator<<(std::ostream &, const B<_T> &);
就可以链接通过。为什么?注意:编译可以通过,但是链接的时候过不了!
这个问题一直困扰于我,希望有高人能给予回答,先谢谢了!
LHL- 已合并 Sheng Jiang 蒋晟Moderator 2010年4月13日 23:36
-
前面已经说过了,函数模板和类模板特化不是一回事。你的友元函数声明特化后成为
ostream & operator << <int> (std::ostream &, const B<int> )
而不是你前面声明的
template<T>
ostream & operator << (std::ostream &, const B<T> )
在C++里面通过模板特化的函数和没有通过模板特化的函数是不同的。例如同时声明两个函数
template<typename T> void f(T);
void f(int);
f(1)调用的是void f(int),而f<int>(1)调用的是template<typename T> void f(T);。
你应该把友元函数声明为函数模板
template<typename T1>
friend std::ostream& operator<<(std::ostream &, const B<T1> &);
The following is signature, not part of post
Please mark the post answered your question as the answer, and mark other helpful posts as helpful.
Visual C++ MVP- 已标记为答案 lhlzhxh 2010年4月14日 3:02
-
啊,太谢谢诸位的热心回答了,我现在终于明白了。
其实,我在模板类B中这样声明友元就可以了:friend std::ostream& operator<< <T> (std::ostream &, const B<T> &);
我的本意是这样的,我要限制std::ostream& operator<< <int>(std::ostream &, const B<int>&)只作为class B<int>的友元,而不能作为class B<float>的友元(不管这样做是不是有必要),也就是说类型要对应(这叫做绑定友元声明),哈哈,我参照《C++ Primer》第三版的说明声明了友元,却出了错误,现在看来那本书是有错误的,它忘记了在operator<<后面加上<T>就像其他绑定的友元函数模板一样。
版主的回复提醒了我,谢谢了。
LHL- 已标记为答案 lhlzhxh 2010年4月14日 3:21
-
这个还需要在前面增加声明
先声明类,再声明operator<<
再定义类,再定义operator,才能生效。 如下:
#include <iostream>
#include <string>
#include <cstdlib>
using namespace::std;
enum CursorMovements {
HOME,
FORWARD,
BACK,
UP,
DOWN,
END
};
template <class Type>
class QueueItem
{
public:
QueueItem(const Type & t): item(t), next(NULL){};
Type item;
QueueItem *next;
static QueueItem *free_list;
static const unsigned QueueItem_chunk;
};
template <class Type>
class Queue;
template <class Type>
ostream & operator<< (ostream & os, const Queue <Type> &q);
template <class Type>
class Queue{
public:
//template<typename T1>
//friend ostream & operator << (ostream & os, const Queue<T1> &);
friend ostream & operator << <Type> (ostream & , const Queue<Type> &);
Queue():front(NULL), back(NULL) {};
~Queue();
Type remove();
void add(const Type &);
bool is_empty() const {return NULL== front;};
//int get_count();
bool is_full();
private:
QueueItem<Type> *front;
QueueItem<Type> *back;
int count;
//
};
/*
template <class Type>
class Foo
{
public:
void bar(){cout<<"this is Foo:: bar"<<endl;};
};*/
template <class Type>
Queue<Type>:: ~Queue()
{
while(!is_empty()){
remove();
}
}
template <class Type>
void Queue<Type>:: add(const Type & val)
{
QueueItem<Type> *ptr = new QueueItem<Type> (val);
//QueueItem<Type> *ptr = new QueueItem<Type>;
if(NULL == ptr){
cout<<"Queue::add malloc failed"<<endl;
return;
}
ptr->next = NULL;
if(is_empty()){
front = back = ptr;
}
else{
back->next = ptr;
back = ptr;
}
count++;
}
template <class Type>
Type Queue<Type>:: remove()
{
if(is_empty()){
cout<<"remove() on empty queue"<<endl;
exit(-1);
}
QueueItem<Type> *ptr = front;
if(NULL == ptr){
cout<<"remove() on empty queue"<<endl;
exit(-1);
}
Type val = ptr->item;
front = front->next;
delete ptr;
return val;
}
/*
int Queue:: get_count()
{
return count;
}*/
template <class Type>
ostream & operator<< (ostream & os, const Queue <Type> &q)
{
os<<"this is operator<<"<<endl;
os<<"<";
QueueItem<Type> *pItem = q.front;
while(NULL != pItem){
os<<"item is "<<pItem->item<<" ";
pItem = pItem->next;
}
os<<">"<<endl;
return os;
}
int main()
{
Queue<int> memList;
int iCnt = 0;
for(iCnt = 0; iCnt < 10; iCnt++){
memList.add(iCnt);
}
cout<<(memList);
while(!memList.is_empty()){
iCnt = memList.remove();
cout<<"remove value is "<<iCnt<<endl;
}
//delete memList;
return 0;
}