Bjarne:為什么不能為模板參數(shù)定義約束?

字號(hào):

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