模板设计目的:尽量减少代码的编辑量/冗余结构
一 C 的大小比较
1. C函数实现
为了实现比对大小的算法,写了三个函数 ,岂不是很啰嗦?
//max.c
#include <stdio.h>
#include <stdbool.h> // for C bool type
bool max_int(int a, int b){
return a > b ? true : false;
}
bool max_double (double a, double b) {
return a > b ? true : false;
}
bool max_pint (int *a , int *b) {
return *a > *b ? true : false;
}
int main(void) {
int a = 99;
int b = 100;
printf("int a : b %d\n",max_int(100,99)); //true
printf("double c : d %d\n",max_double(9.9,10.10)); //false
printf("pint e : f %d\n", max_pint(&a, &b)); //false
return 0;
}
2. C 宏定义表达式
C 宏 :MAX 精简了上面的冗余代码,但是对于第三次调用MAX(&a,&b)调用因为形式上展开后相当于在做地址的大小比较,展开 形如 ((&a > &b) ? true : false),和我的初衷比对 *a > *b ,这个设计存在重大bug,原因在于宏展开时不会检查形参类型,而是简单的进行文本展开
//max.c
#include <stdio.h>
#include <stdbool.h> // for C bool type
#define MAX(A,B) ((A) > (B) ? true : false)
int main(void) {
int a = 99;
int b = 100;
printf("int a : b %d\n",MAX(100,99)); //true
printf("double c : d %d\n",MAX(9.9,10.10)); //false
printf("pint e : f %d\n", MAX(&a, &b)); //?
return 0;
}
3. C宏定义函数
规避风险,使用宏 实现不同算法接口(做到了代码尽量精简,存在使用不到的代码也会被 静态编译到可执行文件中的问题)
实际使用中还是要顾及针对不同类型 需要认为判定选用函数名称
如:MAX_int, MAX_double , MAX_pint … ,存在一定的不便
//max.c
#include <stdio.h>
#include <stdbool.h> // for C bool type
#define MAX(T) \
bool MAX_##T (T a , T b) { \
return a > b ? true : false; \
}
MAX(int)
MAX(double)
//对于指针需要 特殊实现
bool MAX_pint(int *a , int *b) {
return *a > *b ? true : false;
}
int main(void) {
int a = 99;
int b = 100;
printf("int a : b %d\n",MAX_int(100,99)); //true
printf("double c : d %d\n",MAX_double(9.9,10.10)); //false
printf("pint e : f %d\n", MAX_pint(&a, &b)); //false
return 0;
}
4. C 宏定义-一个接近模板的实现
//max.c
#include <stdio.h>
#include <stdbool.h> // for C bool type
#define MAX(T) \
bool MAX_##T (T a , T b) { \
return a > b ? true : false; \
}
MAX(int)
MAX(double)
//对于指针需要 特殊实现
bool MAX_pint(int *a , int *b) {
return *a > *b ? true : false;
}
#define max(T) MAX_##T
int main(void) {
int a = 99;
int b = 100;
printf("int a : b %d\n",max(int)(100,99)); //true
printf("double c : d %d\n",max(double)(9.9,10.10)); //false
printf("pint e : f %d\n", max(pint)(&a, &b)); //false
return 0;
}
二 C++ 函数模板
1. 函数模板 替代C宏实现
其设计形式和使用形式相对C语言宏的版本就简单很多
#include <iostream>
#include <cstdio>
template <typename T>
bool max(T a , T b) {
return a > b ? true : false;
}
//模板重载
template <typename T>
bool max(T *a , T *b) {
return *a > *b ? true : false;
}
//摸板特化/具体化
template <>
bool max(int a , int b) {
using namespace std;
cout <<"max int Always return false" <<endl;
return false;
}
template <>
bool max(double a , double b) {
using namespace std;
cout <<"max double Always return false" <<endl;
return false;
}
//非模板函数
bool max(double a , double b) {
using namespace std;
cout <<"max double Always return true" << endl;
return true;
}
//优先级 非模板 > 模板特化 > 普通模板
int main(void) {
using namespace std;
int a = 99;
int b = 100;
printf("int a : b %d\n",::max<int>(100,99)); //具体化 always false
printf("double c : d %d\n",::max<double>(9.9,10.10)); //显示调用模板,always false
printf("pint e : f %d\n", ::max<int *>(&a, &b)); //false 通用模板重载版本
//::max ,匿名作用域,避免同 std::max 引用冲突, max(a,b), 编译器会做隐式类型推断
cout << ::max(100, 99) << endl; //具体化 int
cout << ::max(9.9, 10.10) << endl; //非模板函数
cout << ::max(&a, &b) << endl;//指针版本
return 0;
}
/*
Log:
max int Always return false
int a : b 0
max double Always return false
double c : d 0
pint e : f 0
max int Always return false
0
max double Always return true
1
0
*/
三 重载解析
以上示例代码我们看到一个事实,通用模板、重载模板、模板特化、非模板函数都可以为调用者提供实现的接口——这对于习惯于C编程来说,需要C++使用者判断究竟调用者会匹配哪一个版本,着实痛苦。
C++ 在函数调用时,编译器决定选用哪一个实现的过程称为 重载解析
优先级 依次为非模板函数 模板特化 通用模板
读者可以参考C++ primer plus V6 8.5.5 一节
方便查表与记忆,具体如下:
调用时如下:
may('B');
备选函数与模板如下:
void may(int); #1
float may(float , float = 3); #2
void may(char); #3
char * may(char *); #4
char may(const char &); #5
template <typename T> void may(const T&); #6
template <typename T> void may (T *); #7
第一步,筛选函数名称为may并且有一个参数的函数,见 #1 ~ #7
第二部,选择匹配的函数列表
匹配类型从优到差依次分为
完全匹配 出现多个完全匹配是错误,编译不通过
提升转换 char 转换为int float 转换为double
标准转换 int 转换为short,char,long转换为double
用户转换 用户定义的转换
完全匹配示例:
void recycle (int); #1
void recycle (int const); #2
void recycle (int &); #3
void recycle (int const &); #4
完全匹配未必一定出错
#3 和#4 一起并不会出错(实际上发生重载)
#1 和 #2 一起会出错