這兩天寫代碼,遇到這么一個模板決議的問題:
有一個類 A,其中有兩個數據成員(方便起見都是 public )。為了從其它部分(比如文件)讀入數據,我為 A 類重載了輸入流操作符。代碼如下所示:
程序1

typedef struct tagA
{
UINT32 biSize;
UINT32 biCount;
} A;
template <typename DataStream>
DataStream& operator>>(DataStream& a_data, A& a_fileHeader)

{
a_data>>a_fileHeader.biSize>>a_fileHeader.biCount;
return a_data;
}
一般使用標準IO流的話,這樣做至少在編譯上是沒有問題的(讀二進制文件不行,后有補充)。
在我的程序中,我目前只是測試時用文件讀取,到后期,肯定會換成其它形式(可能是直接大塊類似的數據整在一起,放在內存中之類),所以我打算為數據源寫一個包裝類,在目前的階段,直接轉到標準IO文件讀取,后期再修改數據源類。因為使用數據源類需要保持與標準IO的寫法一致( cin>>xx ),所以這個類要為每種基本類型重載輸入流操作符。這些重載的代碼結構都是一樣的,只是數據類型不同,因此用模板是最好的,所以一開始,我寫成了下面這個樣子:
程序2
class DataFromFile

{
public:
DataFromFile(CHAR const *a_fileName)
:dataStream(a_fileName, std::ios::binary|std::ios::in)
{ assert(dataStream.good());}
~DataFromFile() 
{ dataStream.close();}
public:
template <typename T>
inline DataFromFile& operator>> (T& a_data) 
{
dataStream.read((CHAR *)&a_data, sizeof(T));
return *this;
}
private:
std::fstream dataStream;
};
但在實際使用時,像下面的語句,就發生了編譯問題:
DataFromFile source("11.bin");
A dest;
source>>dest;
編譯器對這段代碼抱怨,說無法確定使用哪個模板……
當然,我是希望編譯器在這里使用程序一中的非成員模板函數,然后在那個模板函數中,再用程序2中的成員模板函數來實例化基本類型的輸入操作。可是編譯器沒有這么智能,我理解,這里用A做模板參數的話,確實有二義性。
想來想去沒想到好的辦法消除這種二義性,只好修改代碼,去掉其中一個的模板定義。類比地思考一下,標準IO并沒有發生這個問題,因為標準IO的輸入流操作并不是模板函數,而這里的DataFromFile類,明顯使用模板會比較優雅,但二義性的問題不知道怎么解決。最后沒辦法,改成用宏來實現,代碼如下:
程序3
#define InputForBuildIn(Type) \
inline DataFromFile& operator>> (Type& a_data) \

{ \
dataStream.read((CHAR *)&a_data, sizeof(Type)); \
return *this; \
}
class DataFromFile

{
public:
DataFromFile(CHAR const *a_fileName)
:dataStream(a_fileName, std::ios::binary|std::ios::in)
{ assert(dataStream.good());}
~DataFromFile() 
{ dataStream.close();}
public:
InputForBuildIn(INT8)
InputForBuildIn(UINT8)
InputForBuildIn(INT16)
InputForBuildIn(UINT16)
InputForBuildIn(INT32)
InputForBuildIn(UINT32)
private:
std::fstream dataStream;
};
問題是沒有了,但總覺得不是滋味。(不知道有沒有更好的解決辦法?哪位大俠指點下?)
PS:
對 C++ 的標準 IO 流還不熟,在以二進制方式打開文件時,使用 >> 操作符無法讀入數據?一開始的時候調了很久,后來才發現這里可能有問題,轉成使用 .read() 方法來讀數據,就成功了。標準 IO 還是得好好再補補啊。









}
}