函数模板 编译器推断类型,声明和定义都在头文件中,
1.类型参数数组
template <typename T> foo(T* p){ T tmp=*p; return tmp; }
2.非类型模板,常量表达式值
实例化
template <> foo(int *p)函数
判断不出类型的须要显示指定指针
T1 sum(T2,T3) auto val=sum<long>(i,lng) //long对应T1
返回类型code
template <typename It> auto fun(It beg,It end)->decltype(*beg) //返回非指针,元素的值 auto fun(It beg,It end)->typename remove_reference<decltype(*beg)>::type; //typename表示返回类型,非static变量,remove_reference若T为X&,X&&则为X,不然T。 //相似的还有remote_pointer,add_const等
引用ip
int i=42; int &r = i; //左值,左值引用(能取地址的为左值) const int &r3 = i*42 //右值,const&不可改变,可绑定在一个右值上 ,int &r2=i*42则错误 int &&rr2=i*42 //右值,右值引用 template <typename T> void f1(T&), f1(ci)✅ f1(i)✅ f1(5)❌ template <typename T> void f2(const T&), f2(ci)✅ f2(i)✅ f2(5)✅ template <typename T> void f3(T&&), f3(ci)✅ f3(i)✅ f3(5)✅ //f3(i)由于引用折叠:X& &,X& &&,X&& & => X& ; X&& &&=>X&&
std::moveci
int &&rr3=std::move(rr1) //显示将一个左值转移为对应右值引用类型 typename name_reference<T>::type&& move(T&& t){ return static_cast<typename name_reference<T>::type&&>(t) }
std::forwardrem
//从前面看出&&能够接受任何左值或者右值参数,但当参数转发时,第一层T用&&解出后不能用于下层,使用std::forward保持类型 void flip(F f,T1&& t1,T2&& t2){ f(std::forward<T2>(t2),std::forward<T1>(t1)); }
auto与template匹配
template <typename T> void f(ParamType param);
1.paramType既不是指针也不是引用
template <typename T> void f(T param);
若是expr是一个引用,那么先忽略其引用类型;若是有const,volatile修饰符,则一并忽略。编译器
int x = 27; const int cx = x; auto x1 = x; // type is int auto x2 = x; // type is int
2.ParamType是一个指针或者引用,但不是全局引用
忽略引用
template <typename T> void f(T& param); //或T*string
int x = 27; // x is an int const int cx = x; // cx is a const int const int& rx = x; // rx is a reference to x as a const int auto& x1 = x; // int& auto& x2 = cx; // const int& auto& x3 = rx; // const int&
3.ParamType是一个全局引用
template <typename T> void f(T&& param);
若是expr是一个左值,形式为A或者A&。那么T和ParamType的类型都会被推导为A&。
若是expr是一个右值,形式为A&&。则T的类型会被推导为A,而ParamType的类型会被推导为A&&。
auto && x1=x; //x为右值 ,x1为x&&,不然x& ,这个只在for中用,忽略吧
4.数组类型参数
而在形参为引用(包括左值引用和全局引用)的时候则会推导出数组的类型,不会退化为指针io
const char name[] = "J.P.Briggs"; template <typename T> void f1(T& param); f1(name); // T's type and param's type are const char(&)[13]
decltype
在C++ 11中,他惟一的做用就是声明一个返回类型依赖于模板参数的模板函数,这个功能在使用auto时会出错
template <typename Container, typename Index> auto access(Container& c, Index i) -> decltype(auto) { return c[i]; }
C++14
template <typename Container, typename Index> decltype(auto) access(Container&& c, Index i) // final C++14 version { return std::forward<Container>(c)[i]; }
decltype(e)的类型有以下定义:
若是e是一个没有给括号包围的变量名或者一个没有被括号包围的类成员访问,则decltype(e)的类型就是最终访问的变量的类型。若是访问的变量并不存在,则视为错误。
若是; e是一个函数调用或者重载操做符(若是有括号包围,则去除括号),则decltype(e)是最终所调用函数的返回值类型;
不然,若是e是一个左值,且e的类型是T,则decltype(e)为T&;
不然 ,decltype(e)的类型就是e的类型。
const int&& foo(); int i; struct A { double x; }; const A* a = new A(); decltype(foo()) x1 = std::move(i); // type is const int&& decltype(i) x2; // type is int decltype(a->x) x3; // type is double decltype((a->x)) x4 = x3; // type is const double&
template <class T> void printarg(T t) { cout << t << endl; } template <class ...Args> void expand(Args... args) { int arr[] = {(printarg(args), 0)...}; } expand(1,2,3,4);
函数重载
template<typename T, class N> void compare(T num1, N num2) //原模板 template<> void compare(int num1, double num2) //全特化 template<int,double> void compare(int num1, double num2); template<int,class N> void compare(int num1, N num2) //报错 template<class N> void compare(int num1, N num2) //函数重载