typename
编译不确定Container::const_iterator是类型还是对象
/typename就是明确告诉编译器这里是类型,等模板实例化再去找
typename Container::const_iterator it = v.begin();
template<class Container>
void print(const Container& v)
{
//编译不确定Container::const_iterator是类型还是对象
// typename就是明确告诉编译器这里是类型,等模板实例化再去找
//typename Container::const_iterator it = v.begin();
auto it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
cout << endl;
}
非类型模板
在我们使用宏来定义数组大小时,大小是不可以修改的。因此我们从这一角度来认识一个新的模板类型,非类型模板,在使用时,我们可以指定非类型的大小,但是前提必须是常量和整型
//非类型模板参数
//1.必须是常量
//2.必须是整型
//#define N 100
template<class T,size_t N>
class stack
{
public:
void func()
{
N = 22;
}
private:
T _a[N];
int _top;
};
int main()
{
stack<int,10> st1;
st1.func();//非类型模板也是不可以修改的,但是我们可以重新定义
//例如
stack<int,100> st1;
}
类模板特化
前言:
//模板特化
template<class T>
bool Less(T left, T right)
{
return left < right;
}
//template<>
//bool Less<int*>(int* left, int* right)
// bool Less(int* left, int* right)重载
//{
// return *left < *right;
//}
//我们可以通过模板来取代int
template<class T>
bool Less(T* left, T* right)
{
return *left < *right;
}
int main()
{
cout << Less(1, 2) << endl;
int a = 1, b = 2;
//这时我们比较的为地址大小,但实际我们想要比较的为解引用后的值大小
//我们可以模板特化来实现
cout << Less(&a, &b) << endl;
}
接下来,我们来认识以下模板特化
链接: 自定义实现优先级
从我的上个博客的自定义实现的优先级队列来看,我们的特化模板就起到了用途
template<class T1,class T2>
class Data
{
public:
Data() { cout << "Data<T1,T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};
//在上边的模板基础上面进行特化
//假设我针对int double要进行特殊处理
//全特化
template<>
class Data<int,double>
{
public:
Data() { cout << "Data<int,double>" << endl; }
private:
int _d1;
double _d2;
};
//偏特化:特化部分参数
template<class T1>
class Data<T1, double>
{
public:
Data() { cout << "Data<T1,double>" << endl; }
private:
T1 _d1;
double _d2;
};
//偏特化:可能是对某些类型的进一步限制
template<class T1,class T2>
class Data<T1*, T2*>
{
public:
Data() { cout << "Data<T1*,T2*>" << endl; }
private:
T1* _d1;
T2* _d2;
};
template<class T1, class T2>
class Data<T1&, T2&>
{
public:
Data() { cout << "Data<T1&, T2&>" << endl; }
private:
T1 _d1;
T2 _d2;
};
int main()
{
Data<int, int> d1;//普通类模板
Data<int, double> d2;
Data<int*, double> d3;
Data<double, double> d4;
Data<double*, double*> d5;
Data<void*, int*> d6;
Data<int&, double&> d7;
}
模板分离编译
一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。
如果在类外定义时,我们的模板参数没有办法声明,所以就会出现链接错误,这时我们可以显示实例化来解决,但是实用性不高,一般建议
将声明和定义放到一个头文件里
解决办法
//stack.h
#pragma once
#include <deque>
namespace test
{
template<class T, class Container = std::deque<T>>
class stack
{
public:
void push(const T& x);
void pop();
T& top()
{
return _con.back();
}
size_t size()
{
return _con.size();
}
bool empty()
{
return _con.empty();
}
private:
Container _con;
};
class A
{
public:
void func1(int i);
void func2();
};
**//解决办法 声明与定义放同一个文件**
template<class T, class Container>
void stack<T, Container>::push(const T& x)
{
_con.push_back(x);
}
template<class T, class Container>
void stack<T, Container>::pop()
{
_con.pop_back();
}
}
//stack.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "Stack.h"
namespace test
{
template<class T,class Container>
void stack<T, Container>::push(const T& x)
{
_con.push_back(x);
}
template<class T, class Container>
void stack<T, Container>::pop()
{
_con.pop_back();
}
void A::func1(int i)
{
}
**//解决办法 显示实例化 不太推荐**
template
class stack<int>;
template
class stack<double>;
}
//test.c
#include <iostream>
using namespace std;
#include"Stack.h"
int main()
{
test::stack<int> st; // call xxstackxx(0x324242)
st.push(1); // call xxpushi(?)
st.pop();
st.size(); // call xxsizexx(0xdadada)
st.top();
test::A aa;
aa.func1(1); // call xxfunc1xx(?)
//aa.func2(); // call xxfunc2xx(?)
test::stack<double> st1; // call xxstackxx(0x324242)
st1.push(1); // call xxpushi(?)
st1.pop();
return 0;
}