模板
数据结构:能够存在任意类型
算法:能够操作任意类型
模板函数
类实例化 — 对象 模板实例化 ---- 函数代码
参数类型推导(作用在运行期)
decltype(a + b) 自动推导类型 表达式---- 类型
声明 = 定义和声明 都要写在头文件里
#include<iostream>
#include<algorithm>
using namespace std;
class A {
public:
A() = delete;
A(int x) : x(x) {}
A operator+(const A &a) {
return A(x +a.x);
}
private:
int x;
};
auto func(int a, int b)-> int {
return 1;
}
//整一段都是声明(声明定义) 因为是作用在编译期前 必须写在头文件中
//用decltype 确认返回值类型
//每个类型都有构造函数, 但是有些类型没有默认构造所以有bug
/*
template<typename T1, typename T2>
decltype(T1() + U()) add(T1 a, T2 a) {
return a + b;
}
*/
// 返回值后置可以解决多个参数返回值的bug
template<typename T1 ,typename T2>
auto add(T1 a, T2 b)->decltype(a + b) {
return (b + a);
}
int main() {
int();
cout << add<int>(1, 1.1) << endl;//显示调用可以强行的转成int
cout << add(1.1, 1.1) << endl;
decltype(1 + 2) x; // 自动推导类型
cout << typeid(x).name() << endl;
return 0;
}
模板类 模板成员函数
使用的时候必须显示定义类型
#include<iostream>
#include<algorithm>
using namespace std;
template<typename T>
class PRINT {
public:
//template<typename T> 这样就可以实现打印任意类型
PRINT &operator()(T a) {
cout << a << endl;
return *this;
}
};
int main() {
PRINT<int> print;// 必须显示写上类型
print(123);
print(456);
// print("aaa");
PRINT<string> print1;
return 0;
}
实现一个vector模板类
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
class A {
public:
A() = delete; //如果一个类没有默认构造就不能用new进行分配空间
A(int x) : x(x) {}
private:
int x;
};
namespace haizei {
template<typename T>
class vector {
public:
vector(int n = 10):__capacity(n),__size(0), data(nullptr) {
data = (T *)malloc(sizeof(T) * __capacity); // 不能用new 如果没有默认构造就有bug
}
vector(const vector<T> &v) {
__size = v.__size;
__capacity = v.__capacity;
data = (T *)malloc(sizeof(T) * __capacity);
for (int i = 0; i < __size; i++) {
//data[i] = v.data[i]; //malloc出来的空间并没有进行初始化如果这个类没有=运算符就出错了
new(data + i) T(v.data[i]); //原地构造
}
return ;
}
vector(vector<T> &&v) : __capacity(v.__capacity),__size(v.__size), data(v.data){
v.data = nullptr;
v.__size = 0;
}
T &operator[](int ind) {
return data[ind];
}
int size() const {
return __size;
}
~vector() {
if (data) free(data);
__size = 0;
__capacity = 0;
return ;
}
private:
int __size, __capacity;
T *data;
};
};
int main() {
vector<A> v1;
haizei::vector<A> v2;
cout << v1.size() << endl;
cout << v2.size() << endl;
return 0;
}
引用折叠
在模板中 &&是告诉编译器要传引用了 编译器会根据左值右值引用去推导 T的类型是 int & 还是 int &&
只有一个& 只能是左值引用。
奇数左值引用(T 的类型可能推导成为 int & – int &&&) 偶数右值引用(T的类型可能被推导为 int && – int &&&&)
typename remove_reference::type 可以把T类型的引用去掉
#include<iostream>
#include<algorithm>
using namespace std;
namespace haizei {
template<typename T>
void swap(T &a, T &b) {
T c;
c = a; a = b; b = c;
return ;
}
/*
void swap(T &&a, T &&b) {
T c; //这里会出错 在模板中 T&& 不是右值引用 而是告诉编译器要传引用了 所以T c -- T &c 没有初始化报错了
c = a; a = b; b = c;
return ;
}
void swap(T &&a, T &&b) {
typename remove_reference<T>::type c; // 可以把T类型的引用去掉
c = a; a = b; b = c;
return ;
}
*/
};
int main() {
int n = 123, m = 456;
haizei::swap(n, m);
haizei::swap(789, n); //这里出错了 右值绑定在左值引用上
}
模板偏特化 和 特化
类似模板的重载
特化模板的特性差不多没了 要写template<> 告诉编译器还是个模板(类似字面量)处理特殊场景
当显示调用的时候还是要去调用模板 (特化和直接写的区别)
#include<iostream>
#include<algorithm>
using namespace std;
template<typename T1 ,typename T2>
auto add(T1 a, T2 b)->decltype(a + b) { // 返回值后置
return (b + a);
}
template<typename T1 ,typename T2>
auto add(T1 *a, T2 *b)->decltype(*a + *b) { // 模板偏特化 传指针用这个类似重置
return (*b + *a);
}
//模板特化
template<>
int add(int a, int b) {
return a + 2 * b;
}
int main() {
decltype(1 + 2) x; // 自动推导类型
int a = 1, b = 10;
int *p = &a, *q = &b;
return 0;
}
变参模板
递归展开 …ARGS 里面的内容 要有一个递归终止 所以加上一个偏特化版的只穿一个参数的
#include<iostream>
#include<algorithm>
using namespace std;
template<typename T>
void print(T a) {
cout << a << endl;
return ;
}
template<typename T, typename ...ARGS>
void print(T a, ARGS... args) {
cout << a << endl;
print(args...); //递归展开 要有一个出口
return ;
}
int main() {
print(123, "hello", "haizei", 45);
return 0;
}
设计一个工具 如何拿到变参列表里面个个参数的类型 — 递归展开
#include<iostream>
#include<algorithm>
using namespace std;
template<typename T, typename ...ARGS>
struct N_ARGS {
typedef T type;
typedef N_ARGS<ARGS...> rest;
};
template<typename T>
struct N_ARGS<T> {
typedef T type;
typedef T last;
};
template<typename T>
void print(T a) {
cout << a << endl;
return ;
}
template<typename T, typename ...ARGS>
void print(T a, ARGS... args) {
cout << a << "next type" << typeid(typename N_ARGS<ARGS...>::type).name() << endl;
print(args...);
return ;
}
int main() {
print(123, "hello", "haizei", 45);
N_ARGS<int, int ,double, double>::type x;
N_ARGS<int, int ,double, double>::rest::type y;
N_ARGS<int, int ,double, double>::rest::rest::type z;
N_ARGS<int, int ,double, double>::rest::rest::rest::last k;
return 0;
}
优化上面的功能
#include<iostream>
#include<algorithm>
using namespace std;
template<typename T, typename ...ARGS>
struct N_ARGS {
typedef T type;
typedef N_ARGS<ARGS...> rest;
};
template<typename T>
struct N_ARGS<T> {
typedef T type;
typedef T last;
};
template<typename T>
void print(T a) {
cout << a << endl;
return ;
}
template<typename T, typename ...ARGS>
void print(T a, ARGS... args) {
cout << a << "next type" << typeid(typename N_ARGS<ARGS...>::type).name() << endl;
print(args...);
return ;
}
template<int N, typename T, typename ...ARGS>
struct NEW_N_ARGS {
typedef typename NEW_N_ARGS<N - 1, ARGS...>::type type;
static int last() {
return NEW_N_ARGS<N - 1, ARGS...>::last();
}
};
template<typename T, typename ...ARGS>
struct NEW_N_ARGS<1, T, ARGS...> {
typedef T type;
static int last() {
return 0;
}
};
template<typename T>
struct NEW_N_ARGS<1, T> {
typedef T type;
static int last() {return 1;}
};
int main() {
print(123, "hello", "haizei", 45);
//N_ARGS<int, int ,double, double>::type x;
//N_ARGS<int, int ,double, double>::rest::type y;
//N_ARGS<int, int ,double, double>::rest::rest::type z;
//N_ARGS<int, int ,double, double>::rest::rest::rest::last k;
NEW_N_ARGS<1, int, int ,double, double>::type x;
NEW_N_ARGS<2, int, int ,double, double>::type y;
NEW_N_ARGS<3, int, int ,double, double>::type z;
NEW_N_ARGS<4, int, int ,double, double>::type k;
return 0;
}
模板的图灵完备性
用模板去实现功能(累加 判断)
#include<iostream>
#include<algorithm>
using namespace std;
template<int N>
struct is_prime{
static constexpr int r = 0;
};
template<int n>
struct sum {
static constexpr int r = n + sum<n - 1>::r;
};
template<>
struct sum<1> { //递归累加
static constexpr int r = 1;
};
template<int n>
struct getBad {
static constexpr int r = (n <= 5);
};
template<int n>
struct getGood {
static constexpr int r = (n > 5);
};
template<int n, int m> // if分支
struct judge;
template<>
struct judge<1, 0> {
static constexpr char * const r = (char *)"bad";
};
template<>
struct judge<0, 1> {
static constexpr char * r = (char *)"good";
};
template<int n>
struct score {
static constexpr char *r = judge<getBad<n>::r, getGood<n>::r>::r;
};
template<int n>
struct is_even {
static constexpr int r = (n % 2) ? 1 : 0;
};
int main() {
cout << sum<5>::r << endl;
cout << score<10>::r << endl;
cout << score<4>::r << endl;
cout << is_even<3>::r << endl;
return 0;
}
检查素数
#include <iostream>
#include <cmath>
using namespace std;
template <int N, int M>
struct divd {
static constexpr int a = !(N % M) ? 0 : divd<N, M - 1>::a;
};
template <int N>
struct divd<N, 1> {
static constexpr int a = 1;
};
template <int N>
struct is_prime {
static constexpr char *r = divd<N, (int)sqrt(N)>::a == 0 ? (char *)" No" : (char *)" Yes";
};
int main() {
constexpr int a = 2;
constexpr int b = 5;
constexpr int c = 35;
constexpr int d = 17;
constexpr int e = 97;
constexpr int f = 651;
constexpr int g = 23;
constexpr int h = 499;
cout << a << is_prime<a>::r << endl;
cout << b << is_prime<b>::r << endl;
cout << c << is_prime<c>::r << endl;
cout << d << is_prime<d>::r << endl;
cout << e << is_prime<e>::r << endl;
cout << f << is_prime<f>::r << endl;
cout << g << is_prime<g>::r << endl;
cout << h << is_prime<h>::r << endl;
return 0;
}