国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

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

2019-11-17 05:13:24
字體:
來源:轉載
供稿:網友

  可以的,而且方法非常簡單和通用。

  看看這個:

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*類型的某個類型。注重這個定義被精簡到了最小:

  一行命名要檢查的約束,和要檢查的類型

  一行列出指定的要檢查的約束(constraints()函數)

  一行提供觸發檢查的方法(通過構造函數)

  注重這個定義有相當合理的性質:

  你可以表達一個約束,而不用聲明或復制變量,因此約束的編寫者可以用不著去設想變量如何被初始化,對象是否能夠被復制,被銷毀,以及諸如此類的事情。(當然,約束要檢查這些屬性的情況時例外。)

  使用現在的編譯器,不需要為約束產生代碼

  定義和使用約束,不需要使用宏

  當約束失敗時,編譯器會給出可接受的錯誤信息,包括“constraints”這個詞(給用戶一個線索),約束的名字,以及導致約束失敗的具體錯誤(例如“無法用double*初始化Shape*”)。

  那么,在C++語言中,有沒有類似于Can_copy——或者更好——的東西呢?在《C++語言的設計和演變》中,對于在C++中實現這種通用約束的困難進行了分析。從那以來,出現了很多方法,來讓約束類變得更加輕易編寫,同時仍然能觸發良好的錯誤信息。例如,我信任我在Can_copy中使用的函數指針的方式,它源自Alex Stepanov和Jeremy Siek。我并不認為Can_copy()已經可以標準化了——它需要更多的使用。同樣,在C++社區中,各種不同的約束方式被使用;到底是哪一種約束模板在廣泛的使用中被證實是最有效的,還沒有達成一致的意見。

  但是,這種方式非常普遍,比語言提供的專門用于約束檢查的機制更加普遍。無論如何,當我們編寫一個模板時,我們擁有了C++提供的最豐富的表達力量??纯催@個:

template<class T, class B> struct Derived_from {
 static void constraints(T* p) { B* pb = p; }
 Derived_from() { void(*p)(T*) = constraints; }
};

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>();

 Can_compare<int,float>();
 Can_compare<X,B>();
 Can_multiply<int,float>();
 Can_multiply<int,float,double>();
 Can_multiply<B,X>();
 Can_copy<D*,B*>();
 Can_copy<D,B*>();
 Can_copy<int,B*>();
}

// 典型的“元素必須繼續自Mybase*”約束:

template<class T> class Container : Derived_from<T,Mybase> {

// ...

};
  事實上,Derived_from并不檢查來源(derivation),而僅僅檢查轉換(conversion),不過這往往是一個更好的約束。為約束想一個好名字是很難的。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 栾川县| 安龙县| 涿鹿县| 正镶白旗| 东乌| 娱乐| 句容市| 正阳县| 广德县| 文安县| 小金县| 松滋市| 江西省| 大新县| 沐川县| 乌鲁木齐县| 德化县| 巴彦淖尔市| 崇明县| 新营市| 福贡县| 漳平市| 工布江达县| 洛南县| 武安市| 利津县| 桂林市| 巴林右旗| 永寿县| 绥宁县| 靖边县| 房山区| 宁夏| 明溪县| 太仆寺旗| 堆龙德庆县| 夏津县| 邵阳县| 会理县| 安新县| 英吉沙县|