template<class Container> void draw_all(Container& c) { for_each(c.begin(),c.end(),mem_fun(&Shape::draw)); } 假如出現類型錯誤,可能是發生在相當復雜的for_each()調用時。例如,假如容器的元素類型是int,我們將得到一個和for_each()相關的含義模糊的錯誤(因為不能夠對對一個int值調用Shape::draw的方法)。
為了提前捕捉這個錯誤,我這樣寫:
template<class Container> 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)); } 對于現在的大多數編譯器,中間變量p的初始化將會觸發一個易于了解的錯誤。這個竅門在很多語言中都是通用的,而且在所有的標準創建中都必須這樣做。在成品的代碼中,我也許可以這樣寫:
template<class Container>
void draw_all(Container& c) { typedef typename Container::value_type T; Can_copy<T,Shape*>(); // accept containers of only Shape*s for_each(c.begin(),c.end(),mem_fun(&Shape::draw)); } 這樣就很清楚了,我在建立一個斷言(assertion)。Can_copy模板可以這樣定義:
template<class T1, class T2> 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*>檢查T是否是Shape*類型,或者是一個指向由Shape類公共繼續而來的類的對象的指針,或者是被用戶轉換到Shape*類型的某個類型。注重這個定義被精簡到了最小:
template<class T1, class T2> struct Can_copy { static void constraints(T1 a, T2 b) { T2 c = a; b = a; } Can_copy() { void(*p)(T1,T2) = constraints; } };
template<class T1, class T2 = T1> struct Can_compare { static void constraints(T1 a, T2 b) { a==b; a!=b; a<b; } Can_compare() { void(*p)(T1,T2) = constraints; } };
template<class T1, class T2, class T3 = T1> struct Can_multiply { static void constraints(T1 a, T2 b, T3 c) { c = a*b; } Can_multiply() { void(*p)(T1,T2,T3) = constraints; } };
struct B { }; struct D : B { }; struct DD : D { }; struct X { };
int main() { Derived_from<D,B>(); Derived_from<DD,B>(); Derived_from<X,B>(); Derived_from<int,B>(); Derived_from<X,int>();