函數模板 編譯器推斷類型,聲明和定義都在頭文件中,
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) //函數重載