C++模板專門化與重載

  最近在復習C++有關知識,又重新看<<Effective C++>>,收獲頗豐。原來以前看這邊書,好多地方都是淺嘗輒止。<<Effective C++>>條款25:考慮寫出一個不拋出異常的swap函數,涉及到C++模板專門化(Templates?Specialization)和函數重載(overloading)問題,而當重載與模板攪合在一起時,許多問題都變得“模棱兩可”。

  首先回顧<<Effective C++>>條款25:考慮寫出一個不拋出異常的swap函數,想告訴我們什么東西。

  swap函數為我們提供了異常安全編程的方法,以及用來作為處理自我賦值一種常見機制,因此實現一個不拋出異常的swap函數,變得相對重要起來。缺省情況下的swap函數的典型實現如下:

namespace std
{template<typename T>void swap(T& a, T& b){T temp(a);a = b;b = temp;  }        
}

  然后,對于模型數據類型其成員變量是指針,指向一個對象,保存了數據(pointer to implementation手法)。如果copying函數采用了deep copying方法,上面的代碼將會非常低效,因為,只需要互換a與b指針即可。問題是,缺省版本swap對類型無法可知這些信息,因此針對上述情況,需要專門化swap函數。

  1)如果T是class,可以先讓T提供一個swap函數,完成swap功能,然后借由functhon template的全特化,實現專門化的swap函數:

class Widge
{
public:void swap(Wiget& other){using std::swap();swap(pImpl, other.pImpl);}

private:
    WidetImpl* pImpl;
};

//為程序提供一個特化版本的swap:
namespace std 
{
  
template<>
  void swap<Widegt>(Widget& a, Widget& b)
  { a.swap(b);
  
}
}

  上面的代碼很好的與STL容器保持了一致性,因為STL容器也都提供了swap成員函數和std::swap特化版本。

  2)如果Widget與WidgetImpl不是class,而是class template,特化版本的swap函數,我們可能想寫成這樣的形式:

namespace std
{template<class T>void swap<Widegt<T>>(Widget<T>& a, Widget<T>& b)   {a.swap(b);}
}

  然而這個代碼卻無法通過編譯,C++不支持function template的偏特化,我們需要使用模板函數的重載技術:

namespace std
{template<class T>void swap( Widget<T>& a, Widget<T>& b)   //重載了function templates
    {a.swap(b);}
}

  問題似乎已經解決了,嗯,是的,還存在一個問題:用戶可以全特化std內的templates,但是不能新的對象(template、function、class)。解決方法是將這些類與swap函數放到新的命名空間中,這邊便獨立與std命名空間。

--------------------------------------------------------------------華麗分割線--------------------------------------------------------------------

  上面介紹的內容,涉及到以下的內容:1)模板函數;2)重載函數;3)全特化和偏特化。當這些東西交織在一起的時候,我們需要足夠的耐心做區分甄別。

  1)模板類、模板函數與重載

  // Example 1: Class vs. function template, and overloading //// A class templatetemplate<typename T> class X { /*...*/ };           // (a) 類模板// A function template with two overloadstemplate<typename T> void f( T );                  // (b) 函數模板 template<typename T> void f( int, T, double );     // (c)  函數模板重載

  (a)、(b)、(c)均沒有專門化,這些未被專門化的template又被稱為基礎基模板。

  2)特化

  template class可以有全特化與偏特化兩種, template function僅能全特化。

// Example 1, continued: Specializing templates 
//
// A partial specialization of (a) for pointer types 
template<typename T> class X<T*> { /*...*/ };        // A full specialization of (a) for int 
template<> class X<int> { /*...*/ };// A separate base template that overloads (b) and (c) 
// -- NOT a partial specialization of (b), because 
// there's no such thing as a partial specialization 
// of a function template! 
template<class T> void f( T* );             // (d)// A full specialization of (b) for int 
template<> void f<int>( int );              // (e)// A plain old function that happens to overload with 
// (b), (c), and (d) -- but not (e), which we'll 
// discuss in a moment 
void f( double );                           // (f)

  當function template與重載攪合在一起的時候,就存在匹配哪個版本函數的問題,匹配規則如下:

  1)首先查找non template function ,如果在這些函數中匹配成功,則匹配結束(first-class citizens)

  2)否定,在base template function 中查找最匹配的函數,并實例化,如果base template function恰巧有提供全特化版本模板函數,則使用全特化版本(sencond-class citizens)

?將以上兩個規則運用的例子:

// Example 1, continued: Overload resolution 
// 
bool b; 
int i; 
double d;f( b );        // calls (b) with T = bool 
f( i, 42, d ); // calls (c) with T = int 
f( &i );       // calls (d) with T = int 
f( i );        // calls (e) 
f( d );        // calls (f)

  最后一個問題:如何判斷哪個base template function被specialization,再看下面的例子:

// Example 2: Explicit specialization 
// 
template<class T> // (a) a base template 
void f( T );template<class T> // (b) a second base template, overloads (a) 
void f( T* );     //     (function templates can't be partially //     specialized; they overload instead)

template<>        // (c) explicit specialization of (b) 
void f<>(int*);// ...int *p; 
f( p );           // calls (c)

  c是b是全特化,f(p)將會調用,符合人們的一般想法,但是,如果置換b與c的順序,結果就不那么一樣了:

// Example 3: The Dimov/Abrahams Example 
// 
template<class T> // (a) same old base template as before 
void f( T );template<>        // (c) explicit specialization, this time of (a)
void f<>(int*);template<class T> // (b) a second base template, overloads (a) 
void f( T* );// ...int *p; 
f( p );           // calls (b)! overload resolution ignores // specializations and operates on the base // function templates only

  這個時候,c將是a的全特化(編譯器沒看到后面的b的定義)。按照配對規則,首先查找base template function最適合匹配的,b正好最為匹配,并且沒有全特化版本,因此將會調用b。

  重要準則:

  1)如果我們希望客戶化base template function,直接利用傳統的函數形式,如果使用重載形式,那么請不要提供全特化版本。

  2)如果正在編寫一個base template function,不要提供特化和重載版本,將客戶化定制功能下放給用戶。實現方法是,在class template 同static 函數接口:

// Example 4: Illustrating Moral #2 
// 
template<class T> 
struct FImpl;template<class T> 
void f( T t ) { FImpl<T>::f( t ); } // users, don't touch this!

template<class T> 
struct FImpl 
{ static void f( T t ); // users, go ahead and specialize this 
};

  準則2的動機就是利用class template 特化與偏特化功能實現function 特化與偏特化功能。

?

參考文獻:

<<Effective C++>>, Scott Meyers

<<Why Not Specialize Function Templates?>>,??C/C++ Users Journal, 19(7), July 2001

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

    

?

轉載于:https://www.cnblogs.com/wangbogong/p/3249238.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/274094.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/274094.shtml
英文地址,請注明出處:http://en.pswp.cn/news/274094.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android 第十八課 強大的滾動控件 RecyclerView

步驟&#xff1a; 一、添加依賴庫compilecom.android.support:recyclerview-v7:26.1.0 二、在activity_mian.xml中&#xff0c;添加RecyclerView控件&#xff0c;并占據整個頁面。 三、把你要在RecyclerView中展示的內容&#xff0c;設置成一個實體類Fruit&#xff0c;接著為Re…

通過rtcwake命令設置系統S3(休眠到內存)/S4(掛起到硬盤)一段時間后自動喚醒

rtcwake -m disk -s 60 //S4&#xff08;掛起&#xff09;60秒后自動喚醒 rtcwake -m mem -s 60 //S3(休眠&#xff09;60秒后自動喚醒

電商首頁設計的時候,就應該考慮這個

如果有目的去找某一類商品的人幾乎都會從導航或搜索進去了&#xff0c;看首頁的一般是屬于那些還沒想好要買什么東西的人&#xff0c;這些人一般都是漫無目的的瞎逛&#xff0c;看在首頁有沒有特價的或便宜的東西被撿到。 轉載于:https://www.cnblogs.com/wangzong/p/3256555.h…

JavaScript 第一課 JavaScript簡史

1、JavaScript的起源 Java在理論上可以部署在任何環境下&#xff0c;但是JavaScript卻更傾向于只應用在Web瀏覽器。JavaScript是一種腳本語言&#xff0c;通常只能通過Web瀏覽器去完成一些操作而不能像普通意義上的程序那樣獨立運行。因為需要Web瀏覽器進行解釋和執行&#xff…

Linux下的屏保設置 xset s 與 xset dpms

Linux下的屏保設置 xset s 與 xset dpmshttp://bbs.chinaunix.net/archiver/?tid-2112889.html用xset q 可以查看當前屏保的設置情況&#xff0c;黑屏方式的屏保有兩種狀態&#xff1a;1. xset 的s參數后面可接兩個數字參數&#xff0c;前一個即是進入屏保的秒數&#xff0…

ios即時通訊客戶端開發之-mac上安裝MySQL

一、安裝 到MySQL官網上http://dev.mysql.com/downloads/mysql/&#xff0c;下載mysql可安裝dmg版本 比如&#xff1a;Mac OS X ver. 10.7 (x86, 64-bit), DMG Archive 下載完的文件為&#xff1a;mysql-5.6.10-osx10.7-x86_64.dmg 1.點擊&#xff0c;安裝包里的 2.點擊安裝 安…

Android 第十九課 大喇叭--廣播機制----動態注冊監聽網絡變化與靜態注冊實現開機啟動

為了便于進行 系統級別的消息通知&#xff0c;Android引入了一套廣播消息機制。 1、廣播機制簡介&#xff1a;因為Android中的每個應用程序都可以對自己感興趣的廣播盡心注冊&#xff0c;這樣程序只會接收自己所關心的廣播內容&#xff0c;這些廣播來自于系統的&#xff0c;也可…

dbus 和 policykit 實例篇(python)

dbus 和 policykit 實例篇&#xff08;python&#xff09; 使用policykit 的程序一般都有一個dbus daemon程序來完成相關操作&#xff0c;這個dbus daemon 會在系統注冊一個system bus 服務名&#xff0c;用于響應要求root privileged的操作&#xff0c;當dbus請求到達時會先驗…

一個實際的sonar代碼檢查的配置文件

國內私募機構九鼎控股打造APP&#xff0c;來就送 20元現金領取地址&#xff1a;http://jdb.jiudingcapital.com/phone.html內部邀請碼&#xff1a;C8E245J &#xff08;不寫邀請碼&#xff0c;沒有現金送&#xff09;國內私募機構九鼎控股打造&#xff0c;九鼎投資是在全國股份…

JavaScript 第二課 JavaScript語法

本章內容&#xff1a;語句變量和數組操作符條件語句和循環語句函數與對象 ------------------------------------------------------------- 準備&#xff1a; 編寫JavaScript腳本只需要一個普通地文本編輯器和一個Web瀏覽器就足啦。 用JavaScript編寫的代碼必須通過HTML/XHTML…

和菜鳥一起學linux之DBUS基礎學習記錄

轉自&#xff1a;http://blog.csdn.net/eastmoon502136/article/details/10044993 D-Bus三層架構 D-Bus是一個為應用程序間通信的消息總線系統, 用于進程之間的通信。它是個3層架構的IPC 系統&#xff0c;包括&#xff1a; 1、函數庫libdbus &#xff0c;用于兩個應用程序互…

Android 第二十課 廣播機制(大喇叭)----發送自定義廣播(包括發送標準廣播和發送有序廣播)

廣播分為兩種類型&#xff1a;標準廣播和有序廣播 我們來看一下具體這兩者的具體區別&#xff1a; 1、發送標準廣播 我們需要先定義一個廣播接收器來準備接收此廣播才行&#xff0c;否則也是白發。 新建一個MyBroadcastReceiver,代碼如下&#xff1a; package com.example.broa…

八大排序算法

概述 排序有內部排序和外部排序&#xff0c;內部排序是數據記錄在內存中進行排序&#xff0c;而外部排序是因排序的數據很大&#xff0c;一次不能容納全部的排序記錄&#xff0c;在排序過程中需要訪問外存。 我們這里說說八大排序就是內部排序。 當n較大&#xff0c;則應采用…

需求?

1 需求怎樣描述清楚&#xff1f; 利用用例技術&#xff0c;一般這里指的是系統用例&#xff1b;包括以下幾個內容&#xff1a; 用例視圖 系統的功能描述&#xff1b; 用例規約 規定了用戶和系統的交互過程&#xff1b;用戶如何使用系統&#xff1b;用戶如何交互&#xff0c;以及…

Android 第二十一課 RecyclerView簡單的應用之編寫“精美”的聊天頁面

1、由于我們會使用到RecyclerView&#xff0c;因此首先需要在app/build.gradle當中添加依賴庫。如下&#xff1a; apply plugin: com.android.application .... dependencies {....compile com.android.support:recyclerview-v7:26.1.0 } 2、然后開始編寫主頁面&#xff0c;修該…

VS 2008 生成操作中各個選項的差別

近日&#xff0c;在編譯C#項目時經常發現有些時候明明代碼沒錯&#xff0c;但就是編譯不過&#xff0c;只有選擇重新編譯或者清理再編譯才會不出錯&#xff0c;本著求學的態度&#xff0c;搜羅了下VS2008IDE中生成操作的種類以及差別&#xff0c;整理如下&#xff1a;內容(Cont…

dbus-python指南

菜鳥學dbus-python&#xff0c;翻譯dbus-python指南&#xff0c;錯誤之處請在所難免&#xff0c;請諸位不吝賜教&#xff0c;多多指正&#xff01;查看英文原版請點這里。 連接總線Connecting to the Bus方法調用Making method calls代理對象proxy objects接口和方法Interfaces…

JavaScript 第三課 DOM

主要內容&#xff1a; 節點5個常用的DOM方法&#xff1a;getElementById、getElementByTagname、getElementByClassName、getAttribute和setAttribute詳細內容: 1、文檔&#xff1a;DOM中的“D”如果沒有document(文檔),DOM也就無從談起。當創建了一個網頁并把它加載到Web瀏覽器…

源碼編譯安裝Nginx

1.源碼下載 Nginx在github上有一個只讀源碼庫&#xff0c;我獲取的源碼方式為&#xff1a; git clone https://github.com/nginx/nginx.git 2.configure 我下載源碼的時候&#xff0c;github上的源碼的目錄結構為: auto, conf, contrib, docs, misc, src共6個目錄。src目錄是…

SOAP協議初級指南(2)

目前的技術存在的問題&#xff1f;   盡管DCOM和IIOP都是固定的協議&#xff0c;業界還沒有完全轉向其中任何一個協議。沒有融合的部分原因是文化的問題所致。而且在當一些組織試圖標準化一個或另一個協議的時候&#xff0c;兩個協議的技術適用性就被提出質疑。傳統上認為DC…