Function Templates 前言 定義函式樣板 函式樣板的實例化 Template Argument Deduction

Slides:



Advertisements
Similar presentations
C++语言程序设计教程 第5章 构造数据类型 第6章 C++程序的结构.
Advertisements

第一單元 建立java 程式.
C语言程序设计 主讲教师 :张群燕 电话:
Memory Pool ACM Yanqing Peng.
第一章 C语言概述 计算机公共教学部.
编译原理上机实习
陳維魁 博士 儒林圖書公司 第九章 資料抽象化 陳維魁 博士 儒林圖書公司.
第4章 数组 数组是由一定数目的同类元素顺序排列而成的结构类型数据 一个数组在内存占有一片连续的存储区域 数组名是存储空间的首地址
C語言中可變参數的用法——va_list、va_start、va_arg、va_end参數定義
Chapter 5 遞迴 資料結構導論 - C語言實作.
Chapter 7 Search.
Overloaded Functions 前言 處理多載函式宣告的規則 處理多載函式呼叫的規則 多載函式與 scope 函式呼叫的議決.
簡易C++除錯技巧 長庚大學機械系
Derived Class 前言 衍生類別的定義 單一繼承 public, protected, 和 privated 基底類別
编译原理与技术 类型检查 2018/11/21 《编译原理与技术》-类型检查.
Scope & Lifetime 前言 Local Scope Global Functions & Objects
C++ 程式設計— 語言簡介 台大資訊工程學系 資訊系統訓練班.
刘胥影 东南大学计算机学院 面向对象程序设计1 2010~2011第3学期 刘胥影 东南大学计算机学院.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
C語言簡介 日期 : 2018/12/2.
Object-Oriented Programming in C++ 第一章 C++的初步知识
程序设计期末复习 黎金宁
第三章 C++中的C 面向对象程序设计(C++).
前處理指令可以要求前處理器 (preprocessor) 在程式編譯之前,先進行加入其它檔案的內容、文字取代以及選擇性編譯等工作。
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
類別(class) 類別class與物件object.
SQL Stored Procedure SQL 預存程序.
第3章 變數、常數與資料型態 3-1 C語言的識別字 3-2 變數的宣告與初值 3-3 指定敘述 3-4 C語言的資料型態
Methods 靜宜大學資工系 蔡奇偉副教授 ©2011.
2017 Operating Systems 作業系統實習 助教:陳主恩、林欣穎 實驗室:720A.
Java 程式設計 講師:FrankLin.
JAVA 程式設計與資料結構 第四章 陣列、字串與數學物件.
Instructor:Po-Yu Kuo 教師:郭柏佑
明解C++教學手冊 柴田望洋 博士 著 書號:PG20269
第一單元 建立java 程式.
C++程序语言设计 Chapter 3: The C in C++.
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
Classes (2) Lecture 7.
An Introduction to Object-Oriented Programming Using C++
第1讲 C语言基础 要求: (1) C程序的组成 (2) C语言的标识符是如何定义的。 (3) C语言有哪些基本数据类型?各种基本数
潘爱民 C++ Overview 潘爱民
Speaker: Liu Yu-Jiun Date: 2009/4/29
Oop8 function函式.
7.1 C程序的结构 7.2 作用域和作用域规则 7.3 存储属性和生存期 7.4 变量的初始化
Class & Object 靜宜大學資工系 蔡奇偉副教授 ©2011.
Inheritance -II.
樣版.
函數 博碩文化出版發行.
C语言程序设计 李祥 QQ:
C++语言程序设计教程 第2章 数据类型与表达式 第2章 数据类型与表达式 制作人:杨进才 沈显君.
C qsort.
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
第7章 程序的结构 四、生存期与存储属性 五、extern关键字与外部连接属性 六、static关键字与内部连接属性.
第二章 类型、对象、运算符和表达式.
第二讲 基本数据类 型及数组等 此为封面页,需列出课程编码、课程名称和课程开发室名称。
第 9 章 建構函式與解構函式.
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
#include <iostream.h>
方法進階及物件導向基礎 Lecturer: 楊昌樺.
第一讲 面向对象方法学与信息系统建模.
2018 Operating Systems 作業系統實習 助教:林欣穎 實驗室:720A.
本章主題 C++的程式結構 資料型態與宣告 算術運算 簡易的輸入輸出指令 程式編譯(Compile)的過程與原理.
《数据结构与算法设计》第一部分 面向对象的C++程序设计基础.
第四章 陣列、指標與參考 4-1 物件陣列 4-2 使用物件指標 4-3 this指標 4-4 new 與 delete
What is “this”? 在物件導向程式設計中,類別的定義就是在說明如果創建了“這個物件”的話,它會具有那些屬性與功能,以及這些功能是如何實現的。 而所謂的“這個物件”就以 this 來表示。 當我們在JavaScript與jQuery中寫 script 程式(函式)時,“誰”呼叫這個函式,這個“誰”就是該函式中所謂的.
作業系統實習課(二) -Scheduler-Related System Calls-
String類別 在C語言中提供兩種支援字串的方式 可以使用傳統以null結尾的字元陣列 使用string類別
C++程序语言设计 Chapter 14: Templates.
方法(Method) 函數.
InputStreamReader Console Scanner
Presentation transcript:

Function Templates 前言 定義函式樣板 函式樣板的實例化 Template Argument Deduction Explict Template Arguments Template Compilation Models Template Explicit Specialization Overloading Function Templates

前言 C++ 是一個 strongly typed 的電腦語言,這使得我們必須為用意相同但參數資料型態不同的函式,寫出個別的定義。譬如: int min (int x, int y) { return (x < y)? x : y } double min (double x, double y) { return (x < y)? x : y } 查看上面兩個 min 函式,你不難發現到它們的程式碼除了傳回值和參數的資料型態有所不同以外,其它都一樣。 基於以上的觀察,C++ 提供資料型態參數化的函式樣板(function templates)。有了函式樣板, C++ 編譯器會依據函式呼叫時的引數資料型態來自動產生所需的函式定義。

定義函式樣板 函式樣板的定義格式如下: template <type parameter list> function definition 其中 type parameter list 的項目可以是: type parameter: typename type_parameter_name (ANSI C++) class type_parameter_name (舊式的 C++) nontype parameter: type constant_name 項目之間必須用逗號區隔開來。

範例: 以前面的 min 函式為例,我們可以寫出底下的函式樣板: template <typename T> T min (T x, T y) { return (x < y)? x : y } template <class T> T min (T x, T y) { return (x < y)? x : y } 或 其中的 T 是函式樣板的資料型態參數。你可以用任何合法的 C++ 名稱來取代 T,如 S, Type, …, 等等。

範例: 函式樣板的非資料型態參數是用來指定出現在函式樣板定義 中的常數值。 template <typename T, int size> T min (const T (&a)[size]) { T min_val = a[0]; for (int i = 1; i < size; i++) if (a[i] < min_val) min_val = a[i]; return min_val; }

In many ways, templates work like preprocessor macros, replacing the templated variable with the given type. However, there are many differences between a macro like this: #define min(i, j) (((i) < (j)) ? (i) : (j)) and a template: template<typename T> T min (T i, T j) { return ((i < j) ? i : j) } Here are some problems with the macro: There is no way for the compiler to verify that the macro parameters are of compatible types. The macro is expanded without any special type checking.

The i and j parameters are evaluated twice The i and j parameters are evaluated twice. For example, if either parameter has a post-incremented variable, the increment is performed two times. For example, after the evaluations: x = 5; y = 6; z = min(x++, y); variable x becomes 7, not 6. Because macros are expanded by the preprocessor, compiler error messages will refer to the expanded macro, rather than the macro definition itself. Also, the macro will show up in expanded form during debugging.

函式樣板的實例化 當呼叫函式樣板時,C++ 編譯器會依據引數的資料型態,自動產生出所需的函式,這個過程稱為實例化(instantiate)。 int m, x, y; m = min(x, y); template <typename T> T min (T x, T y) { return (x < y)? x : y } T  int int min (int x, int y) { return (x < y)? x : y }

int min (const int (&a)[5]) { … } int ia[] = { 5, 2, 8, 3, 9}; int m = min(ia); 範例: T  int, size  5 template <typename T, int size> T min (const T (&a)[size]) { T min_val = a[0]; for (int i = 0; i < size; i++) if (a[i] < min_val) min_val = a[i]; return min_val; } int min (const int (&a)[5]) { … } double da[] = { 5.0, 2.0, 8.3}; double m = min(da); T  double, size  3 double min (const double (&a)[3]) { … }

把函式樣板指定給函式指標時,C++ 編譯器也會依據引數的資料型態,自動產生出所需的函式。 int (*f) (int, int); f = min; template <typename T> T min (T x, T y) { return (x < y)? x : y } T  int int min (int x, int y) { return (x < y)? x : y }

Template Argument Deduction 如前所述,C++ 編譯器從函式樣板呼叫時的引數型態來產生真實的函式。如果引數的型態和函式樣板的參數型態並不一致時,C++ 編譯器就必須根據一些規則來推導出合適的具體函式。這個過程稱之為 Template Argument Deduction(樣板引數的演繹)。 底下我們用例子來說明這些演繹的規則。

演繹時只檢視引數的資料型態,而不考慮傳回值的資料型態。 template <typename T> T min (T x, T y) { return (x < y)? x : y } double d = min(3, 4); // 產生 int min (int, int) int m = min(3.0, 4.0); // 產生 double min (double , double ) int *ip = min(3, 4); // 產生 int min (int, int),但由於 int 不 // 可指定給 int *,所以此行會造成 // 編譯的錯誤。

如果引數資料型態與函式樣板的參數資料型態不一致,則可能會造成編譯上的錯誤。 template <typename T, int size> T min (const T (&a)[size]) { … } void f (int pval[9]) { // error: Type (&)[] != int * int jval = min(pval); }

template <typename T> T min (T x, T y) { return (x < y)? x : y } unsigned int ui; // error: cannot instantiate min(unsigned int, int) // must be: min(int, int) or // min(unsigned int, unsigned int) int m = min(ui, 1024);

由於陣列可視為指標的一種,因此 C++ 編譯器允許引數資料型態是陣列,而函式樣板的參數資料型態是指標。 template <typename T> T min (T *a, int size) { … } int ia[] = { 5, 2, 8, 3, 9}; int m = min(ia, 5); // 產生 int min(int *, int) double da[10]; double d = min(da, 10); // 產生 double min(double *, int)

演繹時不考慮函式樣板資料型態參數中的 const 和 volatile 宣告。 template <typename T> T min (const T *a, int size) { … } int *ia = new int[10]; int m = min(ia, 10); // 產生 int min(const int *, int) double *da = new double[10]; // 產生 double min(const double *, int) double d = min(da, 10);

Explicit Template Arguments 當無法決定如何從函式樣板產生具體函式時、或需要自定產生某種資料型態的具體函式時,我們可以在呼叫函式樣板時,明白地指定出資料型態參數的種類。指定的格式如下: template_func<explicit type list>(argument list); 譬如: template <typename T> T min (T x, T y) { return (x < y)? x : y } unsigned int ui; // min(unsigned int, unsigned int) unsigned int m = min<unsigned int>(ui, 1024);

範例: template < typename RT, typename T1, typename T2> RT sum (T1 x, T2 y) { … } typedef unsigned int ui_type; char ch; ui_type ui; // error: RT can’t be deduced. ui_type loc1 = sum(ch, ui); // ok: ui_type sum(char, ui_type) ui_type loc1 = sum<ui_type, char, ui_type>(ch, ui);

範例: template < typename RT, typename T1, typename T2> RT sum (T1 x, T2 y) { … } void manipulate(int (*pf)(int, char)); void manipulate(double (*pf)(float, float)); // error: which instantiation of sum? manipulate(sum); // ok manipulate(sum<double, float, float>);

若不會造成混淆的話,< 和 > 之間的資料類型有些可以省略。 template < typename RT, typename T1, typename T2> RT sum (T1 x, T2 y) { … } typedef unsigned int ui_type; char ch; ui_type ui; // ok: ui_type sum(char, ui_type) // T1 和 T2 可由引數的資料型態推演得到 ui_type loc1 = sum<ui_type>(ch, ui); // T1 和 T2 可由 pf 的引數資料型態推演得到 ui_type (*pf)(char, ui_type) = sum<ui_type>;

Template Compilation Models Inclusion Compilation 把函式樣板的定義寫在 .h 標頭檔之中,然後在呼叫函式樣板的程式檔中把這個標頭檔用 include 的方式加進來,讓 C++ 編譯器得以進行函式樣板的 instantiation。 Separation Compilation 把函式樣板的定義寫在一個 .cpp 程式檔之中,然後在呼叫函式樣板的程式檔中宣告此函式樣板。 C++ 編譯器會在編譯後,自動進行所需的 instantiation。 Explicit Instantiation Declaration 由程式設計師指定所需的 instantiation。

Inclusion Compilation Model 把函式樣板的定義寫在 .h 標頭檔之中,然後在呼叫函式樣板的程式檔中用 include 的方式把這個標頭檔加進來。譬如: // file: min.h template <typename T> T min (T x, T y) { return (x < y)? x : y } // prog.cpp #include “min.h” … int m = min(3, 4); 這個方法的優點是:C++ 編譯器可以直接地利用標頭檔中的函式樣板定義來進行 instantiation 的步驟。此外,現有的 C++ 編譯器絕大部份都支援這個方法。

上述方法的缺點是: 當有多個程式檔 include 定義函式樣板的 .h 標頭檔時,C++ 編譯器會重複多次的 instantiations,產生出許多個相同的函式定義,然而其中只有一個被保留下來,其它則捨棄不用。這顯然不是一個有效率的作法。 把函式樣板的定義寫在 .h 標頭檔而暴露在外,顯然不符合所謂 information hiding 的原則。 若函式樣板的定義又臭又長,又有多個程式檔 include 定義它的標頭檔時,C++ 編譯器必須重複地處理,無疑地也會增加 C++ 編譯器許多的負擔。

Separation Compilation Model 把函式樣板的定義寫在一個 .cpp 程式檔之中,然後在呼叫函式樣板的程式檔中宣告此函式樣板。 // file: min.h template <typename T> T min (T x, T y) ; // declaration // prog.cpp #include “min.h” … int m = min(3, 4); // file: min.cpp export template <typename T> T min (T x, T y) { return (x < y)? x : y } 注意行首的 關鍵字 export

上述的方法雖然解決了 inclusion compilation 的缺點,然而許多不符合 ANSI 標準的舊 C++ 編譯器並不支援這個方法。儘管如此,只要你的 C++ 編譯器有支援的話,你還是應該使用這項 ANSI C++ 的新功能。

Explicit Instantiation Declaration template <typename T> T sum (T op1, int op2) { … } // explicit instantiation declaration template int* sum<int *> (int *, int); 產生 int* sum(int *, int);

Template Explicit Specialization template <typename T> T min (T x, T y) { return (x < y)? x : y } 因此我們就寫一個特殊化的函式樣板如下: template<> const char * min (const char *x, const char * y) { return strcmp(x,y) < 0? x : y; }

template <typename T> T min (T x, T y) { return (x < y)? x : y } template<> const char * min (const char *x, const char * y) { return strcmp(x,y) < 0? x : y; } int d = min(2.0, 3.0); // 產生 double min(double, double) int m = min(2, 3); // 產生 int min(int , int ) // 產生 const char * min(const char *, const char *) const char *cp = min(“book”, “apple”);

Overloading Function Templates 如一般函式,我們也可以定義超載函式樣板。譬如: template <typename T> T min(const vector<T>&); // #1 T min(const T*, int); // #2 T min(T, T); // #3 // ordinary function const char *min(const char *, const char *); // #4

vector<int> iv(1024); int m1 = min(iv); // #1 instantiation int ia[1024]; int m2 = min(ia, 1024); // #2 instantiation double d = min(3.0, 4.0); // #3 instantiation float f = min(3.0, 4.0); // #3 instantiation int m3 = min(3, 4); // #3 instantiation const char *cp = min(“Y”, “N”); // #4 instantiation unsigned ui; int m4 = min(3, ui); // error

範例: template <typename T> T min(T, T); template <typename T, typename U> T min(T, U); unsigned ui; int m4 = min(3, ui); // ok int m3 = min(3, 4); // error: ambiguous

範例: template <typename T> // #1, more general T sum(T, int); template <typename T> // #2, more special T sum(T*, int); int ia[1024]; int m2 = sum(ia, 1024); // #2 instantiation