在C++中,術語“轉(zhuǎn)化”(conversion)描述的是從另外一個類型的值(value)獲取一個類型(type)的值的過程??墒怯袝r候你會需要一種不同類型的轉(zhuǎn)化:可能是在你有一個類型時需要獲取一個值,或是其它的類似情形。在C++中做這樣的轉(zhuǎn)化是不尋常的,因為類型域和值域之間隔有有一堵很嚴格的界線。可是,在一些特定的場合,你需要跨越這兩個邊界,本欄就是要討論該怎么做到這個跨越。
映射整數(shù)為類型
一個對許多的generic programming編程風格非常有幫助的暴簡單的模板:
template
struct Int2Type
{
enum { value = v };
};
對傳遞的每一個不同的常整型值,Int2Type“產(chǎn)生”一個不同的類型。這是因為不同的模板的實體(instantiation)是不同的類型,所以Int2Type<0>不同于Int2Type<1>等其它的類型的。此外,產(chǎn)生類型的值被“存放”在枚舉(enum)的成員值里面。
不管在任何時候,只要你需要快速“類型化”(typify)一個整型常數(shù)時,你都可以使用Int2Type。
問題描述:
當需要根據(jù)不同的值選擇不同的行為時,普通的做法是利用if...else...或者case結(jié)構
來實現(xiàn)分支選擇。在一個型別模板化的函數(shù)過程中,則可能出現(xiàn)問題。
看下面的第一部分:
Part 1
如下的范型容器NiftyContainer的元素型別范型化為T。在容器中需要實現(xiàn)元素的賦值行為。非常規(guī)的自定義類型,其復制行為是復雜的。 特別是具有多態(tài)特性的類型和普通的類型,其復制過程不一樣。例如,普通類型可以采用逐位復制的簡單方式,而具有多態(tài)特性(例如含有指針成員)的類對象則不宜采用 這種方式。此處假定普通類型的復制采用拷貝構造函數(shù)方式而多態(tài)的類型則采用一個專門的虛函數(shù)clone來做拷貝。
#include
using namespace std;
class Normal {
int _i;
public:
Normal() { _i = 0; }
Normal(const Normal& nml) { _i = nml._i; }
// other members omitted
};
class Polym {
int *_pi;
Polym(const Polym&); // forbids copy-constructor
void setp(int* i) { _pi = i; }
public:
Polym() { _pi = 0; }
Polym* clone();
// other members omitted
};
template
class NiftyContainer
{
// other members omitted
public:
void DoSomething()
{
T* pSomeObj =new T;
if (isPolymorphic) // branch1
{
T* pNewObj = pSomeObj->clone(); // customized behavior for copying
// some operations on polymorphic object
pNewObj = 0;
}
else // branch2
{
T* pNewObj = new T(*pSomeObj); // using copy-constructor
// some operations on non-polymorphic object
delete pNewObj;
}
delete pSomeObj;
}
// other members omitted
};
int main(int argc, char* argv[])
{
// using the container with elements' type Normal
NiftyContainer nc;
nc.DoSomething(); // error: 類Normal沒有成員函數(shù)clone
// using the container with elements' type Polym
NiftyContainer nc2; //error: 類Polym的copy-constructor private
nc2.DoSomething();
system("PAUSE");
return EXIT_SUCCESS;
}
錯誤解析
按照我們的預期,如果元素類型是多態(tài)的,那么只執(zhí)行branch1部分,否則只執(zhí)行branch2,因為兩種類型的元素有不同的拷貝函數(shù)。但是編譯器可不會理會這些,一律的都要加以編譯,因此出錯了。
對于模板來說,不同的參數(shù)意味著不同的類型。 此外,模板的編譯有一個特性,即沒有用到的模板函數(shù)是不會參與到編譯中的,只進行語法正確性的分析。 函數(shù)可以根據(jù)參數(shù)進行重載。
為了做到“根據(jù)常數(shù)的值(此處就是isPolymorphic)只編譯其中某一個分支(例如branch1),而不編譯其它分支,從而保證最后的代碼中只包含需要的代碼”, 我們可以利用上述的模板編譯特性和函數(shù)重載特性。
template
struct Int2Type { // 創(chuàng)造了這個模板是為了用不同的常數(shù)值產(chǎn)生不同的類型
enum {value=v};
};
template
class NiftyContainer
{
private:
void DoSomething(T* pObj, Int2Type) // function_p
{
T* pNewObj = pObj->Clone();
// some operations on polymorphic object
pNewObj = 0;
}
void DoSomething(T* pObj, Int2Type) // function_n
{
T* pNewObj = new T(*pObj);
// some operations on non-polymorphic object
}
public:
void DoSomething(T* pObj)
{
DoSomething(pObj, Int2Type());
}
// other members are omitted
};
int main(int argc, char* argv[])
{
// using the container with elements' type Normal
NiftyContainer nc;// ok
// using the container with elements' type Polym
NiftyContainer nc2; // ok
system("PAUSE");
return EXIT_SUCCESS;
}
在編譯過程中,根據(jù)傳遞的isPolymorphic模板參數(shù)值的不同,編譯器將選擇實現(xiàn)哪個函數(shù)。 若為true,則實現(xiàn)function_p,而不會嘗試去編譯function_n。 這樣就成功做到了編譯期多態(tài),而不是執(zhí)行期多態(tài)。
這個技術的關鍵點就在于Int2Type模板。
映射整數(shù)為類型
一個對許多的generic programming編程風格非常有幫助的暴簡單的模板:
template
struct Int2Type
{
enum { value = v };
};
對傳遞的每一個不同的常整型值,Int2Type“產(chǎn)生”一個不同的類型。這是因為不同的模板的實體(instantiation)是不同的類型,所以Int2Type<0>不同于Int2Type<1>等其它的類型的。此外,產(chǎn)生類型的值被“存放”在枚舉(enum)的成員值里面。
不管在任何時候,只要你需要快速“類型化”(typify)一個整型常數(shù)時,你都可以使用Int2Type。
問題描述:
當需要根據(jù)不同的值選擇不同的行為時,普通的做法是利用if...else...或者case結(jié)構
來實現(xiàn)分支選擇。在一個型別模板化的函數(shù)過程中,則可能出現(xiàn)問題。
看下面的第一部分:
Part 1
如下的范型容器NiftyContainer的元素型別范型化為T。在容器中需要實現(xiàn)元素的賦值行為。非常規(guī)的自定義類型,其復制行為是復雜的。 特別是具有多態(tài)特性的類型和普通的類型,其復制過程不一樣。例如,普通類型可以采用逐位復制的簡單方式,而具有多態(tài)特性(例如含有指針成員)的類對象則不宜采用 這種方式。此處假定普通類型的復制采用拷貝構造函數(shù)方式而多態(tài)的類型則采用一個專門的虛函數(shù)clone來做拷貝。
#include
using namespace std;
class Normal {
int _i;
public:
Normal() { _i = 0; }
Normal(const Normal& nml) { _i = nml._i; }
// other members omitted
};
class Polym {
int *_pi;
Polym(const Polym&); // forbids copy-constructor
void setp(int* i) { _pi = i; }
public:
Polym() { _pi = 0; }
Polym* clone();
// other members omitted
};
template
class NiftyContainer
{
// other members omitted
public:
void DoSomething()
{
T* pSomeObj =new T;
if (isPolymorphic) // branch1
{
T* pNewObj = pSomeObj->clone(); // customized behavior for copying
// some operations on polymorphic object
pNewObj = 0;
}
else // branch2
{
T* pNewObj = new T(*pSomeObj); // using copy-constructor
// some operations on non-polymorphic object
delete pNewObj;
}
delete pSomeObj;
}
// other members omitted
};
int main(int argc, char* argv[])
{
// using the container with elements' type Normal
NiftyContainer
nc.DoSomething(); // error: 類Normal沒有成員函數(shù)clone
// using the container with elements' type Polym
NiftyContainer
nc2.DoSomething();
system("PAUSE");
return EXIT_SUCCESS;
}
錯誤解析
按照我們的預期,如果元素類型是多態(tài)的,那么只執(zhí)行branch1部分,否則只執(zhí)行branch2,因為兩種類型的元素有不同的拷貝函數(shù)。但是編譯器可不會理會這些,一律的都要加以編譯,因此出錯了。
對于模板來說,不同的參數(shù)意味著不同的類型。 此外,模板的編譯有一個特性,即沒有用到的模板函數(shù)是不會參與到編譯中的,只進行語法正確性的分析。 函數(shù)可以根據(jù)參數(shù)進行重載。
為了做到“根據(jù)常數(shù)的值(此處就是isPolymorphic)只編譯其中某一個分支(例如branch1),而不編譯其它分支,從而保證最后的代碼中只包含需要的代碼”, 我們可以利用上述的模板編譯特性和函數(shù)重載特性。
template
struct Int2Type { // 創(chuàng)造了這個模板是為了用不同的常數(shù)值產(chǎn)生不同的類型
enum {value=v};
};
template
class NiftyContainer
{
private:
void DoSomething(T* pObj, Int2Type
{
T* pNewObj = pObj->Clone();
// some operations on polymorphic object
pNewObj = 0;
}
void DoSomething(T* pObj, Int2Type
{
T* pNewObj = new T(*pObj);
// some operations on non-polymorphic object
}
public:
void DoSomething(T* pObj)
{
DoSomething(pObj, Int2Type
}
// other members are omitted
};
int main(int argc, char* argv[])
{
// using the container with elements' type Normal
NiftyContainer
// using the container with elements' type Polym
NiftyContainer
system("PAUSE");
return EXIT_SUCCESS;
}
在編譯過程中,根據(jù)傳遞的isPolymorphic模板參數(shù)值的不同,編譯器將選擇實現(xiàn)哪個函數(shù)。 若為true,則實現(xiàn)function_p,而不會嘗試去編譯function_n。 這樣就成功做到了編譯期多態(tài),而不是執(zhí)行期多態(tài)。
這個技術的關鍵點就在于Int2Type模板。

