在模板内部定义非成员函数(Define non-member functions inside templates)

来源:互联网 发布:yh线切割编程使用方法 编辑:程序博客网 时间:2024/06/01 09:37

《Thinking in C++》习题16.18,我的实现代码为:

//: C12:IostreamOperatorOverloading.cpp// Example of non-member overloaded operators#include "../require.h"#include <iostream>#include <sstream> // "String streams"#include <cstring>using namespace std;template<typename T, int sz = 5>class IntArray {T i[sz];public:  IntArray() { memset(i, 0, sz* sizeof(*i)); }  int& operator[](int x) {    require(x >= 0 && x < sz,      "IntArray::operator[] out of range");    return i[x];  }  friend ostream&  operator<<(ostream& os, const IntArray& ia);  friend istream&  operator>>(istream& is, IntArray& ia);};template<typename T, int size>ostream& operator<<(ostream& os, const IntArray<T,size>& ia) {  for(int j = 0; j < size; j++) {    os << ia.i[j];    if(j != size -1)      os << ", ";  }  os << endl;  return os;}template<typename T, int size>istream& operator>>(istream& is, IntArray<T,size>& ia){  for(int j = 0; j < size; j++)    is >> ia.i[j];  return is;}int main() {  stringstream input("47 34 56 92 103");  IntArray<int> I;  input >> I;  I[4] = -1; // Use overloaded operator[]  cout << I;} ///:~

但是在VS2010下build时出现以下链接错误:

1>------ Build started: Project: MyCpp, Configuration: Debug Win32 ------
1>  16-18.cpp
1>  LINK : D:\MyProjects\MyCpp\Debug\MyCpp.exe not found or not built by the last incremental link; performing full link
1>16-18.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 IntArray<int,5> const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$IntArray@H$04@@@Z) referenced in function _main
1>16-18.obj : error LNK2019: unresolved external symbol "class std::basic_istream<char,struct std::char_traits<char> > & __cdecl operator>>(class std::basic_istream<char,struct std::char_traits<char> > &,class IntArray<int,5> &)" (??5@YAAAV?$basic_istream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$IntArray@H$04@@@Z) referenced in function _main
1>D:\MyProjects\MyCpp\Debug\MyCpp.exe : fatal error LNK1120: 2 unresolved externals


怎么都想不明白。。。后来翻了一下《Effective C++》Item46 : Define non-member functions inside templates when type conversions are desired. 找到了答案。原因是模板在被调用时才会被实例化,上面代码中,当执行到IntArray<int> I;语句时模板IntArray才被实例化,应该实例化成下面这个样子:

class IntArray {int i[sz];public:  IntArray() { memset(i, 0, sz* sizeof(*i)); }  int& operator[](int x) {    require(x >= 0 && x < sz,      "IntArray::operator[] out of range");    return i[x];  }  friend ostream&  operator<<(ostream& os, const IntArray& ia);  friend istream&  operator>>(istream& is, IntArray& ia);};

这个时候,被实例化的IntArray中有了operator<<和operator>>的声明,但是并没有定义,所以会发生链接错误。修改方法之一是,将该非成员函数的定义放到模板内部,即

//: C12:IostreamOperatorOverloading.cpp// Example of non-member overloaded operators#include "../require.h"#include <iostream>#include <sstream> // "String streams"#include <cstring>using namespace std;template<typename T, int sz = 5>class IntArray {T i[sz];public:  IntArray() { memset(i, 0, sz* sizeof(*i)); }  int& operator[](int x) {    require(x >= 0 && x < sz,      "IntArray::operator[] out of range");    return i[x];  }  friend ostream&  operator<<(ostream& os, const IntArray& ia){for(int j = 0; j < sz; j++) {os << ia.i[j];if(j != sz -1)  os << ", ";  }  os << endl;  return os;  }  friend istream&  operator>>(istream& is, IntArray& ia){for(int j = 0; j < sz; j++)    is >> ia.i[j]; return is;  }};int main() {  stringstream input("47 34 56 92 103");  IntArray<int> I;  input >> I;  I[4] = -1; // Use overloaded operator[]  cout << I;} ///:~

现在就可以编译和链接成功了。


参考

Bruce Eckel.《Thinking in C++》2nd Edition, Vol1. 

Scott Meyers. 《Effective C++》. Item46

0 0