建设网站前准备资料,学校招标网站建设,国内做的比较大的外贸电商网站,做网站开发需要培训吗一、开发者需要对模板参数负责 1.1 为您模板参数提供匹配的操作 在进行模板设计时#xff0c;函数模板或类模板一般只做模板参数#xff08;typename T#xff09;无关的操作为主#xff0c;但是也不见得就不会关联模板参数自身的操作#xff0c;尤其是在一些自定义的数据…一、开发者需要对模板参数负责 1.1 为您模板参数提供匹配的操作 在进行模板设计时函数模板或类模板一般只做模板参数typename T无关的操作为主但是也不见得就不会关联模板参数自身的操作尤其是在一些自定义的数据类型作为模板参数传入时。 看下面这段代码在v1v2时就调用了标准库里的operator操作符比较函数由于typename T是std::string在string类本身是支持了值比较的因此调用正常。
template typename T
inline T mymin(const T v1, const T v2)
{return (v1v2)?v1:v2;
};//会调用bool operator(const T obj1, const T obj2)操作符函数
myminstd::string(guangzhou,shenzhen);那现在再来调整一下代码自定义数据类型DataTest其包含两个int型成员变量现在将该类型作为模板参数传递给mymin函数时会编译异常提示并不支持operator虽然int型支持operator但两个int型的组合在一起就需要模板使用者来为模板参数typename T操作行为负责
class DataTest
{
public:DataTest(const int id_d,const int id_p) : id_domain(id_d),id_point(id_p){};~DataTest(){};int id_domain;int id_point;
};//
DataTest adt(3,4),bdt(3,6);
myminDataTest(adt,bdt); //error, no match for operator 为此我们就需要给DataTest定义其operator操作支持了
class DataTest
{
public:DataTest(const int id_d,const int id_p) : id_domain(id_d),id_point(id_p){};~DataTest(){};int id_domain;int id_point;
};
inline bool operator(const DataTest obj1, const DataTest obj2)
{ if(obj1.id_domainobj2.id_domain)return true;if(obj1.id_domainobj2.id_domainobj1.id_pointobj2.id_point)return true;return false;
};//
DataTest adt(3,4),bdt(3,6);
myminDataTest(adt,bdt); //OK, find operator success 1.2 模板嵌套-类模板作为模板参数 再进一步深化一下代码设计如果给函数模板mymin传递一个类模板A_Test呢同样地为A_Test提供operator操作支持又会怎样。
template typename T1, typename T2
class A_Test
{
public:A_Test(const T1 id_d,const T2 id_p) : id_domain(id_d),id_point(id_p){};~A_Test(){};T1 getDomainID() const{return id_domain;};T2 getPointID() const{return id_point;};
private:T1 id_domain;T2 id_point;
};template typename T1, typename T2
inline bool operator(const A_TestT1,T2 obj1, const A_TestT1,T2 obj2)
{ if(obj1.getDomainID()obj2.getDomainID()) return true;if(obj1.getPointID()obj2.getPointID()obj1.getPointID()obj2.getPointID()) return true;return false;
};
//
A_Testint,float a(3,4.2),b(2,3.8);
myminA_Testint,float (a,b); //OK,没什么区别,只是换成特例化类模板 1.3 友元模板 在外部由于operator是放置在类声明体外声明与定义的它就不能直接使用类模板内的成员变量就需要为它提供额外的访问函数getDomainID、getPointID这样转一手的操作显然不符合inline的诉求其实在标准库里通常类模板会operator声明友元函数函数或类被声明为友元后在类模板内就是真不把自身当外人了甚至是类模板的儿子派生类都比不上。 为了区别前面一种方法我们重新定义一个函数模板mymax在类模板会operator声明友元函数,看下列代码
template typename T1, typename T2
class A_Test
{
public:A_Test(const T1 id_d,const T2 id_p) : id_domain(id_d),id_point(id_p){};~A_Test(){};//template typename T friend bool operator(const T obj1, const T obj2); //why is eroortemplate typename T3, typename T4friend bool operator(const A_TestT3,T4 obj1, const A_TestT3,T4 obj2);
private:T1 id_domain;T2 id_point;
};//
template typename T1, typename T2
inline bool operator(const A_TestT1,T2 obj1, const A_TestT1,T2 obj2)
{ if(obj1.id_domainobj2.id_domain) //直接访问私有成员不含糊return true;if(obj1.id_domainobj2.id_domainobj1.id_pointobj2.id_point) //直接访问私有成员不含糊return true;return false;
};//
template typename T
inline T mymax(const T v1, const T v2)
{return (v1v2)?v1:v2;
};
//
A_Testint,float a(2,4.2),b(2,3.8);
myminA_Testint,float (a,b); //OKA_Teststd::string,std::string a_s(guangzhou,huangpu),b_s(shenzhen,baoan);
if(a_sb_s); //OK
if(a_sb_s); //OK两者都可以实现不看operator内部实现的话 1.4 节省模板的配套操作 当然在实际设计中我们最好还是避免同一模板的多个实例化中隐含的编译进开销
template typename T1, typename T2
inline bool operator(const A_TestT1,T2 obj1, const A_TestT1,T2 obj2)
{ if(obj1.id_domainobj2.id_domain)return true;if(obj1.id_domainobj2.id_domainobj1.id_pointobj2.id_point)return true;return false;
};template typename T
inline T mymax(const T v1, const T v2)
{return (v1v2)?v1:v2;
};//
template typename T
inline T mymin(const T v1, const T v2)
{return (v1v2)?v2:v1; //这样同样也能达成效果
}; 1.5 有度地规划类模板操作符 在设计类模板时需要慎重并认真地思考如何支撑一些通用的操作符调用因为往往类模板设计者和使用者往往不会是同一个作者那么使用者对待类模板时会习惯性地把普通类型的调用习惯用到类模板上来设计其代码时缺发现其实并不支持。例如对于一个常规数据类型输出显示是没有问题的但是对于自定义的类模板那就要想到使用者会有这样的用法习惯给与到支持。
std::cout myminstd::string(guangzhou,shenzhen) std::endl;A_Testint,float a(3,4.2),b(2,3.8);
std::cout myminA_Testint,float (a,b) std::endl; //error 那么这些常用的一些操作函数还是需要通盘考虑和设计的当然使用者如果谨慎他也应该明确知道模板参数行为需要使用者本身去把控。
template typename T1, typename T2
class A_Test
{
public:A_Test(const T1 id_d,const T2 id_p) : id_domain(id_d),id_point(id_p){};~A_Test(){};template typename T3, typename T4friend std::ostream operator(std::ostream os, const A_TestT3,T4 obj);
private:T1 id_domain;T2 id_point;
};//
template typename T1, typename T2
inline std::ostream operator(std::ostream os, const A_TestT1,T2 obj)
{os (;os obj.id_domain , obj.id_point;os );return os;
};
//
A_Testint,float a(2,4.2),b(2,3.8);
std::cout myminA_Testint,float (a,b) std::endl; //OK
//
A_Teststd::string,std::string a_s(guangzhou,huangpu),b_s(shenzhen,baoan);
std::cout myminA_Teststd::string,std::string (a_s,b_s) std::endl; //OK
std::cout mymaxA_Teststd::string,std::string (a_s,b_s) std::endl; //OK 1.7 按需增加必要支持 当然如何把控是模板设计的度都是设计者及使用者的考验例如想更进一步使用上述的模板函数和类模板
A_TestDataTest,DataTest ad_s(DataTest(3,4),DataTest(4,1)),bd_s(DataTest(2,4),DataTest(3,1));std::cout myminA_TestDataTest,DataTest (ad_s,bd_s) std::endl;
std::cout mymaxA_TestDataTest,DataTest (ad_s,bd_s) std::endl; 显然针对DataTest我们需要重新去设计其在上层调用涉及到的、、 这三个操作符函数声明定义后才能被A_Test类模板和mymin、mymax函数模板所识别使用。
inline bool operator(const DataTest obj1, const DataTest obj2)
{ if(obj1.id_domainobj2.id_domain)return true;if(obj1.id_domainobj2.id_domainobj1.id_pointobj2.id_point)return true;return false;
};inline bool operator(const DataTest obj1, const DataTest obj2)
{ if(obj1.id_domainobj2.id_domain)return true;if(obj1.id_domainobj2.id_domainobj1.id_pointobj2.id_point)return true;return false;
};inline bool operator(const DataTest obj1, const DataTest obj2)
{ if(obj1.id_domain!obj2.id_domain)return false;if(obj1.id_point!obj2.id_point)return false;return true;
}; 二、模板隐藏的那些事 2.1 成员函数或成员变量的模板参数 类模板内的成员函数或成员变量类型都可以具有自己的模板参数。
template typename T
class OUT_Class
{
public:void myfun1(const T obj); //和外围模板使用同一个模板参数template typename T1void myfun2(const T1 obj); //自定义了自己的模板参数
};template typename T
void OUT_ClassT::myfun1(const T obj)
{std::cout obj std::endl;
};template typename T //主类的模板参数
template typename T1 //子类的模板参数
void OUT_ClassT::myfun2(const T1 obj)
{std::cout obj std::endl;
};OUT_Classint o_a;
o_a.myfun1(10);
o_a.myfun2double(10.5); 模板在外部定义时具有多个模板参数语句template typename ***一个语句用于自身另一个语句用于外围模板语句测顺序是从外围到内部的。 类模板内的函数模板 或类模板可以在主类模板内部定义也可以放置外部定义。若是函数模板在类内部定义则是一个显式内联函数。
//
template typename T
class OUT_Class
{
pbulic:template typename T1class INT_Class1 //内部直接定义{public:T1 val;};template typename T1class INT_Class2; //外部定义
};//
template typename T
template typename T1
class OUT_ClassT::INT_Class2
{public:T1 val;
};//
OUT_Classint::INT_Class1float o_a_i1;
o_a_i1.val 11.4;
OUT_Classint::INT_Class2float o_a_i2;
o_a_i2.val 12.4; 2.2 联合Union模板 模板设计还允许联合(Union)模板的存在
template typename T
union Chunk
{T obj;unsigned char bytes[sizeof(T)];
};//
union Chunkint uobj;
uobj.bytes[0] 0xff;
std::cout uobj.obj std::endl; 2.3 模板的虚函数问题 类模板内的成员函数模板不能声明为为虚函数因为虚函数调用机制实现使用了一个大小固定的表每个虚函数都对应表的一个入口但成员函数模板在构建虚函数表之前是无法确定的。当然类模板内的普通成员函数设置为虚函数是没问题的。
template typename T
class OUT_Class
{
public://virtual ~V_Class() //OK{};template typename Tvirtual void copy(const T obj) //error{};
}; 2.4 模板的编译链接影响 目前类模板和普通类一样是能和一个实体共享一个名称的虽然要尽量避免这种情况。
template typename T1, typename T2
class A_Test
{
};int A_Test; //OK 大多C编译器都不能支持其具有C连接因此也不建议采用extern来指定编译。并由于模板是采用外部链接的也不能在函数内部声明模板因为编译器无法在链接时确定到该定义。另外也不允许在模板内将模板参数再作为类名、结构名等修饰名称。
extern C template typename T class C_Test{}; //error,不支持extern C template typename T void Func_Test(){};//可行但多余//
void test_in(const int obj)
{template typename T //不能在函数内部声明模板class AC{};//..
};
//
template typename T
class AClass
{class T *inc; //errorfriend class T; //error
}; 2.5 模板的模板参数 前面讲述到模板可以进行嵌套其实模板参数也能进行嵌套即模板的模板参数它的用法和类模板的用法类似
templatetypename T class CX
{public:T val;
};template templatetypename T class CX
void func(CXint obj)
{std::cout obj.val std::endl;
};
//
CXint cx_i;
cx_i.val 20;
func(cx_i); 同时模板的模板参数也支持缺省实参模板
templatetypename Tint
class CX
{public:T val;
};
//template templatetypename T class CX //class 替换成 struct union 是错误的
template templatetypename T typename CX
//void func(CXT obj) //error,模板的模板参数的参数只能被自身其他参数的声明使用
void func(CXint obj)
{std::cout obj.val std::endl;
};
//或者这样更好理解
template typename T,templatetypename T1 typename CX
void func2(CXT obj)
{std::cout obj.val std::endl;
};
//
CX cx_def;
cx_def.val 21;
func(cx_def);//
func2(cx_def); 2.6 模板实参演绎事项 在篇一中就讲述到模板在使用时可以显式指定模板实参或者不指定交给编译器去进行实参演绎因此最好是吧那些无法演绎的试产放在模板参数列表前面从而显式指定这些实参把支持实参演绎的放在后面。
templatetypename T1, typename T2
//inline T2 im_cast(const T1 obj) //尝试一下这样设计呢
inline T1 im_cast(const T2 obj)
{return obj;
};//
double val_ im_castdouble(-30);
std::cout val_ std::endl; 2.7 模板参数是函数模板 对于模板的嵌套还需要说明的是函数模板可以作为函数模板的模板参数
//函数模板嵌套
templatetypename Func, typename T
void doSomething(Func fp,const T obj)
{fp(obj);
};templatetypename T
void doit(const T obj)
{std::cout obj std::endl;
};//
doSomething(doitint,3);
doSomething(doitint,4);2.8 模板参数是函数指针 另外函数模板也可以作为函数指针来使用在具体使用函数指针时指定模板实参即可
//
template typename T
void func3(const T obj)
{std::cout obj std::endl;
};//
void (*pfunc3)(const int obj);
pfunc3 func3int;
pfunc3(15);
//
typedef void (*PFunc)(const float obj);
PFunc pf func3float;
pf(12.5);
(*pf)(13.5); 2.9 命名空间与模板 编译器在模板调用时会依据上下文进行名称查找其查找是有作用域限制的如果模板需要调用另一个命名空间namespace定义数据类型就需要明确指出模板参数所包含的命名空间。
//
namespace pyfree{class PVal{public:int val;};std::ostream operator(std::ostream os, const PVal obj){os (;os obj.val;os );return os;};
};
//
template typename T
void func3(const T obj)
{std::cout obj std::endl;
};
//
pyfree::PVal pval;
pval.val 33;
func3pyfree::PVal(pval); 总之。普通函数及类需要注意的问题函数模板及类模板使用时一样要注意另外由于模板的特殊性还会延展出其很多新的问题点当然也会对编程带来全新的编程架构和编码风格。
三、源码补充 3.1 编译 测试代码包含两个源文件template_test.h和test.cpp通过g test -o test.exe编译运行测试 3.2 源代码 template_test.h
#ifndef _TEMPLATE_TEST_H_
#define _TEMPLATE_TEST_H_#include ostream
#include iostreamclass DataTest
{
public:DataTest(const int id_d,const int id_p) : id_domain(id_d),id_point(id_p){};~DataTest(){};int id_domain;int id_point;
};
inline bool operator(const DataTest obj1, const DataTest obj2)
{ if(obj1.id_domainobj2.id_domain)return true;if(obj1.id_domainobj2.id_domainobj1.id_pointobj2.id_point)return true;return false;
};inline bool operator(const DataTest obj1, const DataTest obj2)
{ if(obj1.id_domainobj2.id_domain)return true;if(obj1.id_domainobj2.id_domainobj1.id_pointobj2.id_point)return true;return false;
};inline bool operator(const DataTest obj1, const DataTest obj2)
{ if(obj1.id_domain!obj2.id_domain)return false;if(obj1.id_point!obj2.id_point)return false;return true;
};inline std::ostream operator(std::ostream os, const DataTest obj)
{os (;os obj.id_domain , obj.id_point;os );return os;
};template typename T1, typename T2
class A_Test
{
public:A_Test(const T1 id_d,const T2 id_p) : id_domain(id_d),id_point(id_p){};~A_Test(){};T1 getDomainID() const{return id_domain;};T2 getPointID() const{return id_point;};template typename T3, typename T4friend std::ostream operator(std::ostream os, const A_TestT3,T4 obj);//template typename T friend bool operator(const T obj1, const T obj2); //why is eroortemplate typename T3, typename T4friend bool operator(const A_TestT3,T4 obj1, const A_TestT3,T4 obj2);
private:T1 id_domain;T2 id_point;
};template typename T1, typename T2
inline std::ostream operator(std::ostream os, const A_TestT1,T2 obj)
{os (;os obj.id_domain , obj.id_point;os );return os;
};template typename T1, typename T2
inline bool operator(const A_TestT1,T2 obj1, const A_TestT1,T2 obj2)
{ if(obj1.getDomainID()obj2.getDomainID()) return true;if(obj1.getPointID()obj2.getPointID()obj1.getPointID()obj2.getPointID()) return true;return false;
};template typename T1, typename T2
inline bool operator(const A_TestT1,T2 obj1, const A_TestT1,T2 obj2)
{ if(obj1.id_domainobj2.id_domain) return true;if(obj1.id_domainobj2.id_domainobj1.id_pointobj2.id_point) return true;return false;
};template typename T
inline T mymin(const T v1, const T v2)
{return (v1v2)?v1:v2;
};template typename T
inline T mymax(const T v1, const T v2)
{return (v1v2)?v1:v2;
};//
template typename T
class OUT_Class
{
public://virtual ~OUT_Class(){};/*template typename Tvirtual void copy(const T obj){};*///void myfun1(const T obj);template typename T1void myfun2(const T1 obj);//template typename T1class INT_Class1 //内部直接定义{public:T1 val;};template typename T1class INT_Class2; //外部定义
};
template typename T
void OUT_ClassT::myfun1(const T obj)
{std::cout obj std::endl;
};template typename T
template typename T1
void OUT_ClassT::myfun2(const T1 obj)
{std::cout obj std::endl;
};template typename T
template typename T1
class OUT_ClassT::INT_Class2
{public:T1 val;
};template typename T
union Chunk
{T obj;unsigned char bytes[sizeof(T)];
};//extern C template typename T class C_Test{}; //error,不支持extern C template typename T void Func_Test(){};
/*
void test_in(const int obj)
{template typename T //不能在函数内部声明模板class AC{};//..
};
template typename T
class AClass
{class T *inc; //errorfriend class T; //error
};
*/
templatetypename Tint
class CX
{public:T val;
};
//template templatetypename T class CX //class 替换成 struct union 是错误的
template templatetypename T typename CX
//void func(CXT obj) //error,模板的模板参数的参数只能被自身其他参数的声明使用
void func(CXint obj)
{std::cout obj.val std::endl;
};template typename T,templatetypename T1 typename CX
void func2(CXT obj)
{std::cout obj.val std::endl;
};
//
templatetypename T1, typename T2
inline T1 im_cast(const T2 obj)
{return obj;
};
//
templatetypename Func, typename T
void doSomething(Func fp,const T obj)
{fp(obj);
};templatetypename T
void doit(const T obj)
{std::cout obj std::endl;
};
//
namespace pyfree{class PVal{public:int val;};std::ostream operator(std::ostream os, const PVal obj){os (;os obj.val;os );return os;};
};
//
template typename T
void func3(const T obj)
{std::cout obj std::endl;
};#endiftest.cpp
#include template_test.h
#include stringint main(int argc, char* argv[])
{std::cout myminstd::string(guangzhou,shenzhen) std::endl;std::cout mymaxstd::string(guangzhou,shenzhen) std::endl;//DataTest adt(3,4),bdt(3,6);myminDataTest(adt,bdt);//A_Testint,float a(2,4.2),b(2,3.8);std::cout myminA_Testint,float (a,b) std::endl;std::cout mymaxA_Testint,float (a,b) std::endl;//A_Teststd::string,std::string a_s(guangzhou,huangpu),b_s(shenzhen,baoan);if(a_sb_s) std::cout a_s is min std::endl;if(a_sb_s) std::cout a_s is max std::endl;//std::cout myminA_Teststd::string,std::string (a_s,b_s) std::endl;std::cout mymaxA_Teststd::string,std::string (a_s,b_s) std::endl;//A_TestDataTest,DataTest ad_s(DataTest(3,4),DataTest(4,1)),bd_s(DataTest(2,4),DataTest(3,1));std::cout myminA_TestDataTest,DataTest (ad_s,bd_s) std::endl;std::cout mymaxA_TestDataTest,DataTest (ad_s,bd_s) std::endl;//OUT_Classint o_a;o_a.myfun1(10);o_a.myfun2double(10.5);//OUT_Classint::INT_Class1float o_a_i1;o_a_i1.val 11.4;OUT_Classint::INT_Class2float o_a_i2;o_a_i2.val 12.4;//union Chunkint uobj;uobj.bytes[0] 0xff;std::cout uobj.obj std::endl; //int A_Test; //OK//CXint cx_i;cx_i.val 20;func(cx_i);CX cx_def;cx_def.val 21;func(cx_def);//func2(cx_i);func2(cx_def);//double val_ im_castdouble(-30);std::cout val_ std::endl;//doSomething(doitint,3);doSomething(doitint,4);//void (*pfunc3)(const int obj);pfunc3 func3int;pfunc3(15);//typedef void (*PFunc)(const float obj);PFunc pf func3float;pf(12.5);(*pf)(13.5);//pyfree::PVal pval;pval.val 33;func3pyfree::PVal(pval);return 0;
};