//模板实参推断
//类型转换与模板类型参数
template<typename T> T fobj(T, T);//实参被拷贝
template<typename T> T fref(const T&, const T&);//引用
string s1("aaaaa");
const string s2("bbbbb");
fobj(s1, s2);//调用fobj(string,string);const被或略
fref(s1, s2);//调用ferf(const string&,const string&)将s1转换为const是允许的
int a[10], b[23];
fobj(a, b);//调用fobj(int*, int*)
fref(a, b);//错误 数组类型不匹配,如果形参是一个引用,数组不会传换成指针。
//使用相同模板参数类型的函数形参
//一个模板类型参数可以用作多个函数形参的类型
//由于只允许有限的几种类型转换,因此传递参数时必须具有相同的类型,否则推断的类型不匹配。
//可以将函数模板定义为两个类型参数
template<typename A, typename B>
int flexibleCompare(const A& v1, const B& v2)
{
if (v1 < v2)return -1;
if (v2 < v1)return 1;
return 0;
}
//正常类型转换应用于普通函数实参
//函数模板可以用普通类型定义的参数,这种函数不进行特殊处理,正常转化为对应的类型
//当调用print时,传递给它的实参会进行正常的类型转换
template<typename T> ostream &print(ostream &os, const T &obj)
{
return os << obj;
}
print(cout, 23);//实例化print(ostream&, int)
ofstream f("asdas");
print(f, 2);//使用print(ostream&, int);将f 装换为ostream&
//函数模板显式实参
//指定显式模板实参
template<typename T1, typename T2, typename T3>
T1 sum(T2, t3);
int i; long lng;
//T1是显式指定的,T2和T3是从函数实参类型推断而来的
//显示模板实参按由左至右的顺序与对应的模板参数匹配
auto val3 = sum<long, long>(i, lng);//long long sun(int,long)
//正常类型转换应用于显示指定的实参
//对于模板类型参数已经显示指定了的函数实参,也可以进行正常的类型转换
long lng;
//以下为模板函数compare(const T &v1,const T &v2)的调用
compare(lng, 1024);//错误 模板参数不匹配
compare<long>(lng, 1024);//正确 实例化compare(long,long)
compare<int>(lng, 1024);//正确 实例化compare(int,int)
//尾置返回类型与类型转换
//可以使用decltype来获取表达式的类型
template<typename It>
auto fcn(It beg, It end)->decltype(*beg)
{
return *beg;
}
//进行类型转换的标准库模板类
//为了使用模板参数的成员,必须typename
template<typename It>
auto fcn2(It beg, It end)->typename remove_reference<decltype(*beg)>::type
{
return *beg;
}
//函数指针和实参推断
template<typename T> int compare(const T&, const T&);
int(*pf1)(const int&, const int&) = compare;
void func(int(*)(const string&, const string&));
void func(int(*)(const int&, const int&));
func(compare);//错误 不知道使用的是那个func版本
func(compare<int>);//正确 显示的指出了使用的版本,传递了compare(const int&, const int&)
//模板实参推断和引用
//从左值引用函数参数推断类型
template<typename T> void f1(T&);//实参必须是一个左值
f1(i);//i是一个int,模板参数类型T是int
f1(ci);//ci是一个const int,T是const int
f1(5);//错误 传递给一个&参数的实参必须是一个左值
template<typename T> void f2(const T&);//可以接受一个右值
//f2中的参数是const&,实参中的const是无关的
f2(i);//i是一个int;模板参数T是int
f2(ci);//ci是一个const int,但模板参数T是int
f2(5);//一个const&参数可以绑定到一个右值,T是int
//从右值引用函数参数推断类型
template<typename T>void f3(T&&);
f3(4);//实参是一个int类型的右值;模板参数T是int
//引用折叠和右值引用参数
//引用折叠只能应用于间接创建的引用的引用,如类型别名或模板参数
//如果一个函数参数是一个指向模板类型参数的右值引用(如T&&)则它可以被当定到一个左值
//如果实参是一个左值,则推断出的模板实参类型将是一个左值引用,且函数参数将被实例化为一个左值引用参数
f3(i);//实参是一个左值,模板参数T是int&
f3(ci);//实参是一个左值,模板参数T是const int&
template<typename T>
void f3(T&& val)
{
T t = val;
t = fcn(t);
if (val == t) {/**/}//若T是引用类型,则一直为true
}
//std::move的定义
template<typename T>
typename remove_reference<T>::type&& move(T&& t)
{
return static_cast<typename remove_reference<T>::type&&>(t);
}
//转发
//某些函数需要将其一个或多个实参连同类型不变地转发给其他函数
template<typename F, typename T1, typename T2>
void flip1(F f, T1 t1, T2 t2)
{
f(t2, t1);
}
void f(int v1, int &v2)
{/**/}
f(2, i);
flip1(f, j, 4);
//使用std::forward保持类型信息
template<typename F, typename T1, typename T2>
void flip(F f, T1 &&t1, T2 &&t2)
{
f(std::forward<T2>(t2), std::forward<T1>(t1));
}
void g(int &&i, int &j)
{/**/}
flip(g, i, 3);