目录
模板
- 使用模板我们就可以写一个函数,而它的参数可以接收多种类型。比如:
// 普通函数, 只能接受 int 类型参数,如果传入其他类型需要类型转换
int sum(int a, int b) {
return (a + b);
}
double sum(double a, double b) {
return (a + b);
}
- 由于不管是 int 参数、double参数,我们的 sum 函数求和内部代码都是一样的 (a + b),那么写多遍就变得麻烦,因此我们可以用模板的代替,只写一次代码,然后编译器会帮我们生成多个版本出来:
// 模板
template<typename T>
T sum(T a, T b) {
return (a + b);
}
// 编译会生成:
int sum(int a, int b) {
return (a + b);
}
double sum(double a, double b) {
return (a + b);
}
- c++的模板是编译期就会展开的,编译期会根据你使用到的类型,生成 template <int> ... 版本、template<double> ... 版本,而原本写的 template<T> ... 其实就是一个配置一样,运行时是不存在的,只是为了告诉编译期应该怎么生成代码。
可变参数模板
- 上面的求和只能2个数求和,那我如果有3个、4个、5个 ... 呢,难道要都写一遍吗:
int sum(int a, int b, int c) {
return (a + b + c);
}
int sum(int a, int b, int c, int d) {
return (a + b + c + d);
}
// ......
- 这时就可以请出可变参数模板来了,我们可以用三个点 来表示参数个数是不确定的:
template<typename T>
T sum(T... args) {
// 展开求和
}
- 但展开这个参数包 args 并不是当成数组遍历的,而是需要通过递归来实现:
template<typename T>
T mysum(T item) {
return item;
}
template<typename T>
T mysum(T item, T... args) {
return mysum(item) + mysum(args);
}
/// 入口
template<typename T>
T sum(T... args) {
return mysum(args);
}
- 最后一个函数 T sum(T... args) 才是我们暴露给用户使用的函数,而它其实是把参数包 args 转给了mysum(T item, T... args),可见原本在 sum 的参数包被拆出第一个参数 item,和剩下的其他参数 args 调用 mysum,假如 args 不存在,则是直接调用了 mysum(T item)
- 而 mysum(T item, T... args) 干嘛了呢, 它将 item 传给 mysum(T item) 处理,并将剩下的传给了"自己"!是的,此时其实就是递归,但请注意,以往我们递归调用的是函数本身,但这次递归不一样,举个例子来看看:
- 假如我们现在要调用 sum 了:sum(1, 2, 3, 4, 5),编译器就会生成接受5个参数的sum:
int sum(int arg0, int arg1, int arg2, int arg3, int arg4);
- 然后sum里面又调用了mysum,编译器接着按照mysum的声明,拆分sum传过来的5个参数为1 + 4生成:
int mysum(int item, int arg1, int arg2, int arg3, int arg4);
- 那接下来就看这个参数列表是 1+4 的mysum里面了,编译器先生成 mysum(T) 对应的 mysum(int):
int mysum(int item);
- 然后1+4的mysum里还把剩下的4个参数递归传给了自己这个模板,那就得把 4 再拆分成 1 + 3 生成mysum
int mysum(int item, int arg2, int arg3, int arg4);
- 到这里你可能已经理解它是怎么拆参数包的了,虽然叫递归,但其实每一次拆包调用的并不是函数本身,而是源于同一个模板生成的少一个参数的函数。
- 再往下就是接着生成:
int mysum(int item, int arg3, int arg4);
int mysum(int item, int arg4);
- 最终参数包 args 只有一个参数时就不用再生成了,它会直接去调用之前生成的 mysum(T item)
不定类型数量
- 前面的可变参数模板还不够彻底,它生成的函数接受的类型只有一个 T,那我能不能每一个参数类型都不一样呢?那么就需要对 template 那一行动手脚了:
template<typename T1, typename T2, typename ...Args>
T1 mysum(T2 item, Args... args);
- 可以看到,template内,我们单独声明了 返回值类型是 T1,第一个参数类型是 T2,而后面的参数类型则不确定,因此用 typename...Args 声明,在 mysum 的参数列表中 (T2 item, Args... args),Args...就表示args的数量是不确定的,由于Args本身类型数量也不确定,因此整体就表示 这里可以接受多个相同或不同类型的参数。
实现printf
- 有了上面的知识,实现printf就简单了,我们可以让它接收 第一个是字符串类型,然后加上多个任意类型的参数,并递归解析输出即可:
template<typename T>
int printNum(const std::string& str, int index, T&& item) {
auto doShift = true;
while (index < str.size()) {
if (index == (str.size() - 1) || str[index] != '%') {
cout << str[index];
++index;
}
else if(doShift) {
doShift = false;
++index;
switch (str[index]) {
case 's':
case 'd':
cout << item;
break;
}
++index;
}
else {
return index - 1;
}
}
return index - 1;
}
template<typename T, typename... Args>
int printNum(const std::string& str, int index, T&& item, Args&&... args) {
index = printNum(str, index, item);
return printNum(str, index + 1, std::forward<Args>(args)...);
}
template<typename ...Args>
void myPrintNum(const std::string& str, Args&&... args) {
int index = 0;
while (index < str.size()) {
if (str[index] != '%') {
cout << str[index];
++index;
}
else {
break;
}
}
index = printNum(str, index, std::forward<Args>(args)...);
++index;
while (index < str.size()) {
cout << str[index];
++index;
}
}
int main() {
// 调用,参数数量允许和字符串内数量不同,不会出错
myPrintNum("output: %d, %d, %d, %d ---", 123, 100.123, true);
return 0;
}
Cenforce 100mg tablets for sale Purchase Cenforce Online Cenforce 150 mg online
Kamagra 100mg price: kamagra.win – Kamagra Oral Jelly
http://viagras.online/# order viagra
Generic Tadalafil 20mg price cialist.pro Tadalafil Tablet
buy Viagra over the counter: Buy Viagra online cheap – Generic Viagra for sale
http://cialist.pro/# Generic Tadalafil 20mg price
sildenafil oral jelly 100mg kamagra kamagra Kamagra tablets
buy cialis pill: Cialis 20mg price in USA – Cialis without a doctor prescription
Cenforce 150 mg online: Buy Cenforce 100mg Online – order cenforce
https://kamagra.win/# cheap kamagra
http://viagras.online/# Cheap generic Viagra
Levitra 20 mg for sale Cheap Levitra online Levitra online USA fast
https://levitrav.store/# Levitra 20 mg for sale
lisinopril 20mg discount buy lisinopril 20 mg online zestril brand
http://finasteride.store/# buy propecia without a prescription
buy generic ciprofloxacin: ciprofloxacin order online – ciprofloxacin generic price
tamoxifen hot flashes tamoxifen therapy tamoxifen vs clomid
https://finasteride.store/# buy generic propecia no prescription
https://cytotec.club/# Abortion pills online
zestril generic: lisinopril 20 mg tablet price – lisinopril 5 mg brand name
common side effects of tamoxifen liquid tamoxifen benefits of tamoxifen
http://ciprofloxacin.tech/# buy cipro cheap
best generic lisinopril: cheapest lisinopril 10 mg – zestoretic 10 12.5
tamoxifen adverse effects where to buy nolvadex alternative to tamoxifen
http://ciprofloxacin.tech/# buy ciprofloxacin over the counter
https://nolvadex.life/# tamoxifen for men
buy cytotec over the counter: buy cytotec in usa – buy cytotec over the counter
http://lisinopril.network/# prinivil cost
buy cytotec pills online cheap cytotec abortion pill buy misoprostol over the counter
tamoxifen for sale: does tamoxifen cause bone loss – tamoxifen and bone density
aromatase inhibitor tamoxifen nolvadex gynecomastia tamoxifen adverse effects
https://finasteride.store/# buy cheap propecia prices
lisinopril 10mg daily: lisinopril 2.5 tablet – lisinopril 2.5 mg price
buy generic ciprofloxacin ciprofloxacin order online buy cipro
http://ciprofloxacin.tech/# cipro 500mg best prices
buy lisinopril online: 40 mg lisinopril for sale – lisinopril oral
antibiotics cipro cipro 500mg best prices buy cipro cheap
http://finasteride.store/# propecia order
buy cipro online canada: buy cipro – ciprofloxacin generic price
http://ciprofloxacin.tech/# buy cipro online
ciprofloxacin generic cipro for sale ciprofloxacin 500mg buy online
https://ciprofloxacin.tech/# antibiotics cipro
cost of tamoxifen: nolvadex vs clomid – what is tamoxifen used for
tamoxifen reviews tamoxifen and grapefruit natural alternatives to tamoxifen
http://nolvadex.life/# aromatase inhibitor tamoxifen
get generic propecia prices buying generic propecia price buying generic propecia online
get propecia without a prescription: generic propecia pill – cost of cheap propecia without dr prescription
https://finasteride.store/# order generic propecia without dr prescription
generic propecia no prescription order propecia pills propecia without prescription
https://ciprofloxacin.tech/# ciprofloxacin order online