可以的,而且方法非常簡單和通用。
看看這個:
template
void draw_all(Container& c)
{
for_each(c.begin(),c.end(),mem_fun(&Shape::draw));
}
如果出現(xiàn)類型錯誤,可能是發(fā)生在相當復(fù)雜的for_each()調(diào)用時。例如,如果容器的元素類型是int,我們將得到一個和for_each()相關(guān)的含義模糊的錯誤(因為不能夠?qū)σ粋€int值調(diào)用Shape::draw的方法)。
為了提前捕捉這個錯誤,我這樣寫:
template
void draw_all(Container& c)
{
Shape* p = c.front(); // accept only containers of Shape*s
for_each(c.begin(),c.end(),mem_fun(&Shape::draw));
}
對于現(xiàn)在的大多數(shù)編譯器,中間變量p的初始化將會觸發(fā)一個易于了解的錯誤。這個竅門在很多語言中都是通用的,而且在所有的標準創(chuàng)建中都必須這樣做。在成品的代碼中,我也許可以這樣寫:
template
void draw_all(Container& c)
{
typedef typename Container::value_type T;
Can_copy(); // accept containers of only Shape*s
for_each(c.begin(),c.end(),mem_fun(&Shape::draw));
}
這樣就很清楚了,我在建立一個斷言(assertion)。Can_copy模板可以這樣定義:
template struct Can_copy {
static void constraints(T1 a, T2 b) { T2 c = a; b = a; }
Can_copy() { void(*p)(T1,T2) = constraints; }
};
Can_copy(在運行時)檢查T1是否可以被賦值給T2。Can_copy檢查T是否是Shape*類型,或者是一個指向由Shape類公共繼承而來的類的對象的指針,或者是被用戶轉(zhuǎn)換到Shape*類型的某個類型。注意這個定義被精簡到了最?。?BR> 一行命名要檢查的約束,和要檢查的類型
一行列出指定的要檢查的約束(constraints()函數(shù))
一行提供觸發(fā)檢查的方法(通過構(gòu)造函數(shù))
注意這個定義有相當合理的性質(zhì):
你可以表達一個約束,而不用聲明或復(fù)制變量,因此約束的編寫者可以用不著去設(shè)想變量如何被初始化,對象是否能夠被復(fù)制,被銷毀,以及諸如此類的事情。(當然,約束要檢查這些屬性的情況時例外。)
使用現(xiàn)在的編譯器,不需要為約束產(chǎn)生代碼
定義和使用約束,不需要使用宏
當約束失敗時,編譯器會給出可接受的錯誤信息,包括“constraints”這個詞(給用戶一個線索),約束的名字,以及導(dǎo)致約束失敗的詳細錯誤(例如“無法用double*初始化Shape*”)。
看看這個:
template
void draw_all(Container& c)
{
for_each(c.begin(),c.end(),mem_fun(&Shape::draw));
}
如果出現(xiàn)類型錯誤,可能是發(fā)生在相當復(fù)雜的for_each()調(diào)用時。例如,如果容器的元素類型是int,我們將得到一個和for_each()相關(guān)的含義模糊的錯誤(因為不能夠?qū)σ粋€int值調(diào)用Shape::draw的方法)。
為了提前捕捉這個錯誤,我這樣寫:
template
void draw_all(Container& c)
{
Shape* p = c.front(); // accept only containers of Shape*s
for_each(c.begin(),c.end(),mem_fun(&Shape::draw));
}
對于現(xiàn)在的大多數(shù)編譯器,中間變量p的初始化將會觸發(fā)一個易于了解的錯誤。這個竅門在很多語言中都是通用的,而且在所有的標準創(chuàng)建中都必須這樣做。在成品的代碼中,我也許可以這樣寫:
template
void draw_all(Container& c)
{
typedef typename Container::value_type T;
Can_copy
for_each(c.begin(),c.end(),mem_fun(&Shape::draw));
}
這樣就很清楚了,我在建立一個斷言(assertion)。Can_copy模板可以這樣定義:
template
static void constraints(T1 a, T2 b) { T2 c = a; b = a; }
Can_copy() { void(*p)(T1,T2) = constraints; }
};
Can_copy(在運行時)檢查T1是否可以被賦值給T2。Can_copy
一行列出指定的要檢查的約束(constraints()函數(shù))
一行提供觸發(fā)檢查的方法(通過構(gòu)造函數(shù))
注意這個定義有相當合理的性質(zhì):
你可以表達一個約束,而不用聲明或復(fù)制變量,因此約束的編寫者可以用不著去設(shè)想變量如何被初始化,對象是否能夠被復(fù)制,被銷毀,以及諸如此類的事情。(當然,約束要檢查這些屬性的情況時例外。)
使用現(xiàn)在的編譯器,不需要為約束產(chǎn)生代碼
定義和使用約束,不需要使用宏
當約束失敗時,編譯器會給出可接受的錯誤信息,包括“constraints”這個詞(給用戶一個線索),約束的名字,以及導(dǎo)致約束失敗的詳細錯誤(例如“無法用double*初始化Shape*”)。

