template<typenameT>intcompare(const T &v1,const T &v2){if(v1 < v2)return-1;if(v2 < v1)return1;return0;}//即使用于指针也正确的版本template<typenameT>intcompare(const T &v1,const T &v2){if(less<T>()(v1,v2 ))return-1;if(less<T>()(v1,v2 ))return1;return0;}
函数模板和类模板成员函数的定义通常放在头文件中。
当编写模板时,代码不能是针对特定类型的,但模板代码通常对其所使用的类型有一些假设。
保证传递给模板的实参支持模板所要求的操作,以及这些操作在模板中能正确工作,是调用者的责任。
16.1.2 类模板
编译器不能为类模板推断模板参数类型。
一个类模板的每个实例都形成一个独立的类。
类模板用来实例化类型,而一个实例化的类型总是包含模板参数的。
默认情况下,对于一个实例化了的类模板,其成员只有在使用时才被实例化。
//实例化Blob<int>和接受initializer_list<int>的构造函数
Blob<int> squares ={0,1,2,3,4,5,6,7,8,9};//实例化Blob<int>::size() constfor(size_t i =0; i!= squares.size();++i)squares[i]= i*i;//实例化Blob<int>::operator[](size_t)//如果一个成员函数没被使用,则它不会被实例化
在类模板自己的作用域中,可以直接使用模板名而不提供实参。
//后置:递增/递减对象但返回原值template<typenameT>
BlobPtr<T> BlobPtr<T>::operator++(int){//此处无须检查;调用前置递增时会进行检查BlobPtr ret =*this;//保存当前值++*this;//推进一个元素;前置++检查递增是否合法return ret;//返回保存的状态}
typedefdouble A;template<typenameA,typenameB>voidf(A a, B b){A tmp = a;//tmp的类型为A的类型,而非doubledouble B;//错误:重声明模板参数B}//错误:非法重用模板参数名Vtemplate<typenameV,typenameV>//...
//3个calc都指向相同的函数模板template<typenameT> T calc(const T&,const T&);//声明template<typenameU> U calc(const U&,const U&);//声明//模板的定义template<typenameType>
Type calc(const Type& a,const Type& b){/*...*/}
template<typenameT> ostream &print(ostream &os,const T &obj){return os << obj;}print(cout,42);//实例化print(ostream&, int)
ofstream f("output");print(f,10);//使用print(ostream&,int);将f转换为ostream&
16.2.2 函数模板显式实参
只有尾部(最右)参数的显式模板实参才可以忽略,而且前提是它们可以从函数参数推断出来。
//编译器无法推断T1,它未出现在函数参数列表中template<typenameT1,typenameT2,typenameT3>
T1 sum(T2,T3);//T1是显式指定的,T2和T3是从函数实参类型推断而来的auto val3 =sum<longlong>(i,lng);//long long sum(int,long)//糟糕的设计:用户必须指定所有三个模板参数template<typenameT1,typenameT2,typenameT3>
T3 alternative_sum(T2,T1);//错误auto val3 =alternative_sum<longlong>(i,lng);//正确:显式指定了所有三个参数auto val2 =alternative_sum<longlong,int,long>(i,lng);
对于模板类型参数已经显式指定了的函数实参,也进行正常的类型转换。
long lng;compare(lng,1024);//错误:模板参数不匹配compare<long>(lng,1024);//正确:实例化compare(long,long)compare<int>(lng,1024);//正确:实例化compare(int,int)
16.2.3 尾置返回类型与类型转换
template<typenameIt>???&fcn(It beg, It end){//处理序列return*beg;//返回序列中一个元素的引用}vector<int> vi ={1,2,3,4,5};
Blob<string> ca ={"hi","bye"};auto&i =fcn(vi.begin(), vi.end());//fcn应该返回int&auto&s =fnc(ca.begin(), ca.end());//fcn应该返回string&//尾置返回允许我们在参数列表之后声明返回类型//在编译器遇到函数的参数列表之前,beg并不存在template<typenameIt>autofcn(It beg,It end)->decltype(*beg){//处理序列return*beg;//返回序列中一个元素的引用}
//为了使用模板参数的成员,必须用typenametemplate<typenameIt>autofcn2(It beg, It end)->typenameremove_reference<decltype(*beg)>::type
{//处理序列return*beg;//返回序列中一个元素的拷贝}
//Args是一个模板参数包; rest是一个函数参数包//Args表示零个或多个模板类型参数//rest表示零个或多个函数参数template<typenameT,typename... Args>voidfoo(const T &t,const Args&... rest);//编译器会推断包中参数的数目int i =0;double d =3.14; string s ="how now brown cow";foo(i,s,42,d);//包中有三个参数foo(s,42,"hi");//包中有两个参数foo(d,s);//包中有一个参数foo("hi");//空包//编译器会为foo实例化出四个不同的版本voidfoo(constint&,const string&,constint&,constdouble&);voidfoo(const string&,constint&,constchar[3]&);voidfoo(constdouble&,const string&);voidfoo(constchar[3]&);
//用来终止递归并打印最后一个元素的函数//此函数必须在可变参数版本的print定义之前声明template<typenameT>
ostream &print(ostream&os,const T &t){return os << t;//包中最后一个元素之后不打印分隔符}//包中除了最后一个元素之外的其他元素都会调用这个版本的printtemplate<typenameT,typename... Args>
ostream &print(ostream &os,const T &t,const Args&... rest){os << t <<", ";//打印第一个实参returnprint(os,rest...);//递归调用,打印其他实参}print(cout, i, s,42);//包中有两个参数
据估计,未来十年内,联网设备的数量将增长到近400亿台。无论是追踪共享出行车辆的移动、改善食品追溯性、监控制造设施,还是保障家庭安全,物联网 ( Internet of Things,IoT) 对企业和消费者来说都已经成为一项关键技术。…
文章目录 ARM 工具链命名规范详细介绍1. arch(架构)2. vendor(供应商)3. os(操作系统)4. abi(应用二进制接口)ABI(应用二进制接口)常见的 ABI 类型工具链命名约定ExamplesABI 合规性ARM 工具链命名规范详细介绍
ARM 工具链的命名规范指示了 GCC 工具链的构建目的和所…
突然有天,发现线上的项目有块功能缺失,我以为是我优化的时候不小心改坏了什么代码,导致的,先上图 第一反应,就以为天塌了,完全无从入手,然后我就找了之前的离职的同事,他又给我两个包,让我打成依赖扔进去,这两个包分别是scratch-blocks,scratch-vm,
然后我就使用了npm link np…