C 11之模板別名 函式模板的預設模板引數

2021-07-25 18:59:37 字數 3273 閱讀 6745

在c++98/03裡,我們可以通過typedef 關鍵字定義乙個型別的別名,比如 typedef unsigned int uint_t;在這裡我們定義了unsigned int型別的別名和uint_t,在以後需要使用unsigned int的時候我們都可以用uint_t替換,但是uint_t僅僅是作為unsigned int的乙個別名,如下的定義是不合法的:

typedef unsigned int uint_t;

void func(unsigned int);

void func(uint_t);

上面的func函式是乙個不合法的函式過載,雖然使用typedef定義乙個型別的別名很方便,但是typedef在使用上存在一些限制,比如說typedef無法重定義乙個模板的別名。

考慮下面例子,我們在實際程式設計中經常使用到stl中的map,我們map的string型別的資料作為map的key,我們想根據string型別的key對映為乙個string,int,long等型別的資料.

typedef std::mapmap_t;

//...

typedef std::map < std::string, std::string > map_str;

//...

如果需要對映成10中型別的資料,我們就需要利用typedef定義10個具體型別的別名,但是考慮到map的key值始終是變的,我們是否像下面一樣可以用typedef+模板來定義乙個別名呢

template typedef std::mapmap;

mapmap_i;

mapmap_str;

遺憾的是上述的定義不能通過編譯,也就是c++ 98/03並不支援這樣的操作,而通常是通過乙個包裹類的方式來實現上述的需求:

template struct alias_map

;alias_map::map map_t;

alias_map::map map_str;

通過包裹類的方法雖然可以實現上述的需求,但是一看**就覺得,這個**可讀性差,不就是定義乙個變數嗎?還需要整乙個包裹類來封裝下,增加**裡不說,看著都煩,小幸運的是c++11終於讓你可以不用通過上述這種臃腫的方式來實現這個需求了。c++11中,新增了乙個特性就是可以通過使用using來為乙個模板定義別名,比如說上述的需求,使用c++11就可以這樣實現:

template using alias_map = std::map < std::string, t > ;

alias_mapmap_t;

alias_mapmap_str;

系不繫看著舒服很多啊,頓時神清氣爽,在c++11中,允許使用using關鍵字為乙個模板來定義別名,實際上using包含了typedef的所有功能,來看下使用using關鍵字和typedef關鍵字定義普通型別別名的用法。

typedef unsigned int uint_t;

using uint_t = unsigned int;

typedef std::mapmap_t;

using map_t = std::map < std::string, int > ;

可以看到在對普通型別的別名定義上,兩種方法的使用基本等效,唯一不同的僅僅是定義的語法,using使用起來就像是賦值,但是在定義函式函式指標的時候,using看起來可讀性要稍微好一點,比如:

typedef void(*func)(int, int);

using func = void(*)(int, int);

可能突然看起來使用using的方式來定義乙個函式指標有點怪,但是習慣了之後會發現使用using這種賦值的方式更適用開發人員的思考方式。下面再顯示乙個通過typedef和using方式分別來定義乙個函式模板的例子:

templatestruct funcst

;funcst::func func_typedef;

templateusing func_using = void(*func)(t, t);

func_usingfunc_using;

可以看到通過using定義模板別名的語法,僅僅是在普通型別別名語法基礎上增加了template引數列表,通過using可以輕鬆的建立乙個模板的別名,而不需要像c++98/03那樣增加乙個包裹類。但是需要額外注意的是使用using或者typedef僅僅是定義乙個別名,不會創造新型別。

在c++98/03裡,類模板是支援預設的模板引數的,比如:

templatestruct foo

;

但是在c++98/03中確實不能支援函式模板的預設模板引數:

template //error in c++98/03 default template arguments

void func(void)

現在這個限制在c++11中已經解除,上述的定義在c++11中可以直接使用了。在函式模板中當所有模板引數都有預設引數時,函式的呼叫就如同普通的函式呼叫,但是對於類末班而言,哪怕所有模板引數都有預設建構函式在使用時還是必須在模板名後跟隨<>來例項化。

c++11中函式的預設模板引數在使用規則上和其他的預設引數也有一些區別,普通函式的預設引數必須寫在引數列表的最後,而函式的模板引數就沒有這個限制,因此當使用預設模板引數和模板引數自動推導時就顯示十分靈活,可以指定函式中的一部分引數是預設引數,另一部分採用自動推導。比如:

template r func(u val)

int _tmain(int argc, _tchar* argv)

但是如果在使用函式模板時如果顯示指定模板的引數,由於模板引數的填充順序是自左向右的,因此像下面這樣的呼叫返回的型別是long型別:

func(123); //func返回型別是填充型別long

這個細節雖然簡單,但是在多個預設模板引數和多個模板引數自動推導穿插使用時會容易被忽略掉,造成使用上的一些意外,建議在使用的時候盡量還是**預設模板引數寫在模板引數的末尾;另外當預設模板引數和自動引數推導同時使用時,若函式模板無法推導出引數型別時,編譯器將使用預設模板引數,否則將使用自動推導的引數型別。這個跟函式的預設引數使用規則是一致的,比較好理解。

模板別名以及預設模板引數是在泛型程式設計中的一些小細節,是c++11對c++98/03一些細節上的提公升,因此介紹的篇幅不多,主要是在使用的時候若可以的話可以通過這些小技巧增加**可讀性,減少**冗餘。

C 11 函式模板的預設模板引數

類模板 通用的類描述 使用泛型來定義類 進行例項化時,其中的泛型再用具體的型別替換。函式模板 通用的函式描述 使用泛型來定義函式 進行例項化時,其中的泛型再用具體的型別替換。c 98標準中兩者的區別 函式模板和類模板在c 98標準中一起被引入,兩者區別主要在於 在類模板宣告時,標準允許其有預設模板引...

C 11 模板函式的預設模板引數

一 深入理解c 11 裡的兩句話 c 98中,引入了函式模板和類模板,允許模板類宣告的時候有預設模板引數,但是不支援函式模板。c 11 開始支援,區別是模板函式的預設模板引數不需要 從右往左 依次指定。特別,模板引數的預設形參不是模板引數推導的依據。二 include 模板類的預設模板引數的順序從右...

c 11模板別名using

對於冗長或複雜的識別符號,如果能夠建立其別名將很方便。以前c 為此提供了typedef typedef std vector iterator ittype c 11提供了另一種建立別名的語法 using using ittype std vector iterator ittype 差別在於新語法...