C++ 回忆录11 Template
2013-11-18 17:23
471 查看
1.Generic programing reliese on a form of polymorphism,the polymorphism in OOP appliese at run time to classes releate by inheritance. we can write code that use such class in ways that ignore the type differences among the base and the derived classes.As
long as we use references or pointers to the base type.
in C++ ,templates are the foundation for generic programming.
2.Defining a function template.
template <typename T,class P> int tmpFunctionTest(const T &v1,const T &v2)
{
.....
return 0;
}
a template definition starts with the keywords template followed by a template parameter list,which is a comma-separated list of one or more template parameters .
the template parameter list cannot be empty.
a template parameter can be a type parameter which represent a generic type, or the nontype parameter which represent a constant expression.will set the example later.
there is no difference between class and typename in this context.
when use a function template, the compiler infers what template argumennts to bind to the template parameters, once the compiler determines the actual template arguments,in instantiatesan instance of the function template
for us.
3.inline function template.
tempate <typename T> inline T min(const T&, const T &);// pls notice the template keyword postion, is in front of the keyword inline.
4.Define a class template
.h
template <class Type> class Queue
{
public:
Queue();// default constructor
Type & front();
const Type & front()const; //overload version fo front member.
void push(const Type&);
void pop();
bool empty()const;
private :
//....
};// do remember the semicolomn in the final square bracket.
when using class template, we must explicitly specify arguments for the template parameters:
Queue<int> qi;
Queue<vector<double>> qc;
Queue<string>qs;
Essentially, the compiler rewrites our Queue class replacing Type by the specified actual type . in this case, the compiler will instantiate 3 version class.
5.Template parameter scope:
template parameter live in the template declarement start till end. follow the normal name-hiding rules.
typedef double T;
template <class T> T cal(cons T &a, const T &b)
{
typedef double T;//error, redeclare template parameter T
T tmp=a;// tmp is template type,not global T define as double.
return tmp;
}
template <class V,class V> V cal(...);//also error. V can only use once in template parameter list.
6.Template Declarations.
we can declare a template without defining it.
template <class T> int compare(const T&,const T &);
the names of the template parameters need not be the same across declarations and the definition of the same template:
template <class T>T cal(const T&,const T&);
template<class U> cal(const U&,const U&);
//actual definition of the template
template <class Type> cal(const Type&a,const Type&b){......};
template <typenameT,U>...//Error
7.the keyword typename was added to C++ as part of the Standard C++,so older programer are more likely to use keyword class exclusively.
8.a class may define type member. so in template if we use that type member ,we need to explicit .
template <class Para,class U> Para fcn(Para * array, U value)
{
Para:;size_type * p;//if Para::size_type is a type,then a declaration
//if Para:;size_type is an object,then multiplication
}
by default, the compliler assumes that such names name data member,not types.
if we want the compiler to treat size_type as a type,then we must explicityly tell the compiler to do so:
template <class Para,class U> Para fcn(Para * array, U value)
{
typename Para:;size_type * p; //ok, declare p to be a pointer
}
Of cousre, this declaration puts an obligation on the types used to instantiate fcn: Those types must have a member named size_type that's a type.
9.Nontype template parameters.
nontype parameters are replaced by values when the function is called.
//initialize elements of and array to zero.
template <class T, size_t N >void array_init(T (¶)
)
{
for (size_t i=0;i!=N;i++)
{
para[i]=0;
}
}
a template nontype parameter is a constant value inside the template definition.
int x[42];
double y[10];
const int sz=40;
int k[sz+2];
array_init(x);//instantiate array_init(int(&)[42])
array_init(y);//instantiate array_init(double(&)[10])
array_init(k);//no need to instantiate again, use the same array_init(int(&)[42]) version
when array_init is called, the compiler figures out the value of the nontype parameter from the array argument.
that means we do not call like this array_init(x,42); //because in the function definition, we only define one parameter:T (¶)
, we did not define like this
array_init(T * para, N)... do rember notice these difference.
It's a syntax for array references - you need to use
EDIT: Some clarification.
These three are different ways of declaring the same function. They're all treated as taking an
This only accepts arrays of 100 integers. You can safely use
This is parsed as an "array of references" - which isn't legal.
in C/C++ when you pass an array you are passing a pointer
比如:int a[3];
int (&b)[3] = a;
b本身是一个引用,引用的是数组名a.
如果要是int& b[3];
这样是建立一个数组,数组的元素是引用这样C++不支持,因为引用不可以作数组中的元素。引用不可以作为数组元素的原因是它不支持传统意义的复制。
传统意义的复制:
int a = b;
a和b在内存中分别占用,内容一致。
如果
int &a = b;
这种复制,内存中a并不分配新的内存。
10.whether the generated program is legal depends on the operations used in the function and the operations supported by the type(s) used.
template <typename T> compare(const T & v1, const T & v2)
{
if(v1<v2)return -1;
if(v2<v1) return 1;
return 0;
}
our simple compare function illustrate 2 important principles for writing generic code:
.the parameter to the template are const reference
.the test in the body use only < comparisons.
by using const reference,we allow types that do not allow copying, Most types including the build-in type and except for the IO type, all the library types we have used do allow copying.
if(v1<v2)return -1;
if(v1>v2) return 1; // in this version, we require the type also support > operator .
11.The process of generating a type-specific instance of a template is known as instantiationg. when we write Queue<int> qi; the compiler automatically creates a class
named Queue<int>, this class is an independent class type, has no relationship to nor any special access to the members of any other Queue type.
Queue qs; //error, class template argument are required.
when use a function template ,the compiler will usually infer the template argument for us, no need to specify the argument type explictly.
compare (1,0)// bind int
compare (1.0,2.7)//bind to double.
// of course you can specify the argument explictyly
compare<int>(1,0);
compare<double>(1.0,2.7);
12:parameter conversion on template
short s1,s2;
int i1,i2;
compare(i1,i2);//ok instanstiate compare(int,int)
compare(s1,s2)//ok instanstiate compare (short ,short);
if compare is a normal function not a template, then the second call ,s1,s2 will be promted to int. but for template, do not have the conversion from short to int.in general, arguments art not converted to match an exsiting instantiation,instead a new
instance will be gernerated. There are only 2 kinds of conversion that the compile will perform rather that generating a new instantiation;
--->).const conversions:
a.const reference or pointer argument, a non constant reference or pointer can be conerted to const.
b.nonconst reference argument, constant reference parameter, the constant will be ignore.
template <typename T> T fobj(T,T); //argument are copied
template <typename T> T fref(const T &, const T &);// reference argument
string s1("a value");
const string s2("another value");
fobj(s1,s2); //call f(string,string) , const on s2 are ignore.
fref(s1,s2);//s1 will convert to const .
----->)array or function to poiner conversion:
int a[10],b[42];
fobj(a,b);//ok. call f(int * ,int *), an array argument will be treated as a pointer to its first element
fref(a,b);// error, when a parameter is a references (section 7.24 P240), the arrays are not converted to pointer
13.normal conversion apply for nontemplate argument
template <typename T> T sum(const T & op1,int op2)
{
}
// in this template op2 is not a template argument, so normal conversion can be applied to this argument.
14. function pointer determine the template argument
template <typename T> int compare (const T &, const T &);
// pf1 points to the instantiation int compare (const int & ,const int &)
int (* pf1) (const int &, const int &)=compare; //
it's an error if the template argument can't be determined from the function pointer type:
//overloaded version of func()/, each take a difference function pointer type as its argument
void func(int (*)(const string &, const string &));
void func(int (*)(const int &,const int &));
func(compare); //error, can't determine the compare argument type
need this:
func(compare<int>); //need explict
/// example of functon pointer and template , also here we review the function pointer define syntax
template <typename T> int compare1(const T & v1, const T & v2);
void testfunctionpointer(int (*)(const int &,const int &));
main()
{
testfunctionpointer(compare1);
//or
int (*pf1)(const int &,const int &)=compare1;
testfunctionpointer(pf1);
}
template <typename T> int compare1(const T & v1, const T & v2)
{
return v1+v2+10;
}
void testfunctionpointer(int (*PF)(const int &,const int &))
{
int a=20,b=30;
cout<<"test function pinter"<<PF(a,b)<<endl;
}
15.Function template explict argument,
consider this case,
template<typename T, typename U> ??? sum(T,U); // we need to ensure the the return type is larger enough of contain the reture value, how?
one approach is choose one of them, when call the function,
template <typename T,typename U> T sum(T,U);//now T as return type
int i,short s;
sum(static_case<int>(s), i); // ok, instantiate int sum(int,int); 也就是说调用的时候自己control,,,如果不记得就麻烦了,,,
another approach is introduced a third template parameter.
template<typename T, typename U, typename K> K sum(T,U);
int 12,i1;
long val3=sum<long>(i1,i2);
//rember this poor desing
template <typename T1,typename T2,typename T3> T3 sum2(T2,T1);
int i,long lng;
long val3=sum2(i,lng); //error,
long val3=sum2<long,int,long>(i,lng); //ok, but ,,,最好是按parameter define order ,define the template argument order.
16.P643 template compliation models
这种行为看起来十分奇怪,尤其是当关键字
7.
有人能解释一下为什么
不过,这个情况有个不错的历史原因。C语言诞生自B语言,而在B语言中只有&而没有&&运算符。当Ritchie引入&&运算符时,他们希望原有的B语言端的代码能够正常运行,因此使&的优先级低于==。
C11 future:
vector<list<int>> i; // if not in C11 need a space between two closing template expressions vector<list<int>> i
long as we use references or pointers to the base type.
in C++ ,templates are the foundation for generic programming.
2.Defining a function template.
template <typename T,class P> int tmpFunctionTest(const T &v1,const T &v2)
{
.....
return 0;
}
a template definition starts with the keywords template followed by a template parameter list,which is a comma-separated list of one or more template parameters .
the template parameter list cannot be empty.
a template parameter can be a type parameter which represent a generic type, or the nontype parameter which represent a constant expression.will set the example later.
there is no difference between class and typename in this context.
when use a function template, the compiler infers what template argumennts to bind to the template parameters, once the compiler determines the actual template arguments,in instantiatesan instance of the function template
for us.
3.inline function template.
tempate <typename T> inline T min(const T&, const T &);// pls notice the template keyword postion, is in front of the keyword inline.
4.Define a class template
.h
template <class Type> class Queue
{
public:
Queue();// default constructor
Type & front();
const Type & front()const; //overload version fo front member.
void push(const Type&);
void pop();
bool empty()const;
private :
//....
};// do remember the semicolomn in the final square bracket.
when using class template, we must explicitly specify arguments for the template parameters:
Queue<int> qi;
Queue<vector<double>> qc;
Queue<string>qs;
Essentially, the compiler rewrites our Queue class replacing Type by the specified actual type . in this case, the compiler will instantiate 3 version class.
5.Template parameter scope:
template parameter live in the template declarement start till end. follow the normal name-hiding rules.
typedef double T;
template <class T> T cal(cons T &a, const T &b)
{
typedef double T;//error, redeclare template parameter T
T tmp=a;// tmp is template type,not global T define as double.
return tmp;
}
template <class V,class V> V cal(...);//also error. V can only use once in template parameter list.
6.Template Declarations.
we can declare a template without defining it.
template <class T> int compare(const T&,const T &);
the names of the template parameters need not be the same across declarations and the definition of the same template:
template <class T>T cal(const T&,const T&);
template<class U> cal(const U&,const U&);
//actual definition of the template
template <class Type> cal(const Type&a,const Type&b){......};
template <typenameT,U>...//Error
7.the keyword typename was added to C++ as part of the Standard C++,so older programer are more likely to use keyword class exclusively.
8.a class may define type member. so in template if we use that type member ,we need to explicit .
template <class Para,class U> Para fcn(Para * array, U value)
{
Para:;size_type * p;//if Para::size_type is a type,then a declaration
//if Para:;size_type is an object,then multiplication
}
by default, the compliler assumes that such names name data member,not types.
if we want the compiler to treat size_type as a type,then we must explicityly tell the compiler to do so:
template <class Para,class U> Para fcn(Para * array, U value)
{
typename Para:;size_type * p; //ok, declare p to be a pointer
}
Of cousre, this declaration puts an obligation on the types used to instantiate fcn: Those types must have a member named size_type that's a type.
9.Nontype template parameters.
nontype parameters are replaced by values when the function is called.
//initialize elements of and array to zero.
template <class T, size_t N >void array_init(T (¶)
)
{
for (size_t i=0;i!=N;i++)
{
para[i]=0;
}
}
a template nontype parameter is a constant value inside the template definition.
int x[42];
double y[10];
const int sz=40;
int k[sz+2];
array_init(x);//instantiate array_init(int(&)[42])
array_init(y);//instantiate array_init(double(&)[10])
array_init(k);//no need to instantiate again, use the same array_init(int(&)[42]) version
when array_init is called, the compiler figures out the value of the nontype parameter from the array argument.
that means we do not call like this array_init(x,42); //because in the function definition, we only define one parameter:T (¶)
, we did not define like this
array_init(T * para, N)... do rember notice these difference.
It's a syntax for array references - you need to use
(&array)to clarify to the compiler that you want a reference to an array, rather than the (invalid) array of references
int & array[100];.
EDIT: Some clarification.
void foo(int * x); void foo(int x[100]); void foo(int x[]);
These three are different ways of declaring the same function. They're all treated as taking an
int *parameter, you can pass any size array to them.
void foo(int (&x)[100]);
This only accepts arrays of 100 integers. You can safely use
sizeofon
x
void foo(int & x[100]); // error
This is parsed as an "array of references" - which isn't legal.
in C/C++ when you pass an array you are passing a pointer
比如:int a[3];
int (&b)[3] = a;
b本身是一个引用,引用的是数组名a.
如果要是int& b[3];
这样是建立一个数组,数组的元素是引用这样C++不支持,因为引用不可以作数组中的元素。引用不可以作为数组元素的原因是它不支持传统意义的复制。
传统意义的复制:
int a = b;
a和b在内存中分别占用,内容一致。
如果
int &a = b;
这种复制,内存中a并不分配新的内存。
10.whether the generated program is legal depends on the operations used in the function and the operations supported by the type(s) used.
template <typename T> compare(const T & v1, const T & v2)
{
if(v1<v2)return -1;
if(v2<v1) return 1;
return 0;
}
our simple compare function illustrate 2 important principles for writing generic code:
.the parameter to the template are const reference
.the test in the body use only < comparisons.
by using const reference,we allow types that do not allow copying, Most types including the build-in type and except for the IO type, all the library types we have used do allow copying.
if(v1<v2)return -1;
if(v1>v2) return 1; // in this version, we require the type also support > operator .
11.The process of generating a type-specific instance of a template is known as instantiationg. when we write Queue<int> qi; the compiler automatically creates a class
named Queue<int>, this class is an independent class type, has no relationship to nor any special access to the members of any other Queue type.
Queue qs; //error, class template argument are required.
when use a function template ,the compiler will usually infer the template argument for us, no need to specify the argument type explictly.
compare (1,0)// bind int
compare (1.0,2.7)//bind to double.
// of course you can specify the argument explictyly
compare<int>(1,0);
compare<double>(1.0,2.7);
12:parameter conversion on template
short s1,s2;
int i1,i2;
compare(i1,i2);//ok instanstiate compare(int,int)
compare(s1,s2)//ok instanstiate compare (short ,short);
if compare is a normal function not a template, then the second call ,s1,s2 will be promted to int. but for template, do not have the conversion from short to int.in general, arguments art not converted to match an exsiting instantiation,instead a new
instance will be gernerated. There are only 2 kinds of conversion that the compile will perform rather that generating a new instantiation;
--->).const conversions:
a.const reference or pointer argument, a non constant reference or pointer can be conerted to const.
b.nonconst reference argument, constant reference parameter, the constant will be ignore.
template <typename T> T fobj(T,T); //argument are copied
template <typename T> T fref(const T &, const T &);// reference argument
string s1("a value");
const string s2("another value");
fobj(s1,s2); //call f(string,string) , const on s2 are ignore.
fref(s1,s2);//s1 will convert to const .
----->)array or function to poiner conversion:
int a[10],b[42];
fobj(a,b);//ok. call f(int * ,int *), an array argument will be treated as a pointer to its first element
fref(a,b);// error, when a parameter is a references (section 7.24 P240), the arrays are not converted to pointer
13.normal conversion apply for nontemplate argument
template <typename T> T sum(const T & op1,int op2)
{
}
// in this template op2 is not a template argument, so normal conversion can be applied to this argument.
14. function pointer determine the template argument
template <typename T> int compare (const T &, const T &);
// pf1 points to the instantiation int compare (const int & ,const int &)
int (* pf1) (const int &, const int &)=compare; //
it's an error if the template argument can't be determined from the function pointer type:
//overloaded version of func()/, each take a difference function pointer type as its argument
void func(int (*)(const string &, const string &));
void func(int (*)(const int &,const int &));
func(compare); //error, can't determine the compare argument type
need this:
func(compare<int>); //need explict
/// example of functon pointer and template , also here we review the function pointer define syntax
template <typename T> int compare1(const T & v1, const T & v2);
void testfunctionpointer(int (*)(const int &,const int &));
main()
{
testfunctionpointer(compare1);
//or
int (*pf1)(const int &,const int &)=compare1;
testfunctionpointer(pf1);
}
template <typename T> int compare1(const T & v1, const T & v2)
{
return v1+v2+10;
}
void testfunctionpointer(int (*PF)(const int &,const int &))
{
int a=20,b=30;
cout<<"test function pinter"<<PF(a,b)<<endl;
}
15.Function template explict argument,
consider this case,
template<typename T, typename U> ??? sum(T,U); // we need to ensure the the return type is larger enough of contain the reture value, how?
one approach is choose one of them, when call the function,
template <typename T,typename U> T sum(T,U);//now T as return type
int i,short s;
sum(static_case<int>(s), i); // ok, instantiate int sum(int,int); 也就是说调用的时候自己control,,,如果不记得就麻烦了,,,
another approach is introduced a third template parameter.
template<typename T, typename U, typename K> K sum(T,U);
int 12,i1;
long val3=sum<long>(i1,i2);
//rember this poor desing
template <typename T1,typename T2,typename T3> T3 sum2(T2,T1);
int i,long lng;
long val3=sum2(i,lng); //error,
long val3=sum2<long,int,long>(i,lng); //ok, but ,,,最好是按parameter define order ,define the template argument order.
16.P643 template compliation models
4.变量的定义与使用形式相似
这一点对记住如何定义十分复杂的事物非常有用,举个例子,一个指向包含十个整形的数组的指针应该是int *api[10]还是
int (*pai)[10]呢?像你使用它的方式一样定义它即可,只需要记住
[]操作符的优先级高于
*(很自然就可以记住),然后你就明白那个括号是需要的了。(译者注:前者是指针数组,包含十个指向整形的指针。)
6. 全局变量默认是外部的
你会说“用全局变量可不是个好习惯!”。但在嵌入式系统中不同。举个例子,你有一个名为timer.c的文件,其中有个全局变量
int counter,在另一个文件
state_machine.c中,有另一个
counter。如果你碰巧忘记了在它们之前加上’static’,它们就是同一个变量,你根本察觉不到,没有Warning,没有任何提示……
这种行为看起来十分奇怪,尤其是当关键字
extern就在手边的时候。不过当你熟悉
static的两种不同的意义后,就可以轻易避免这种情况了。不过这依然十分令人讨厌。
7. static
的两种不同的意义
有人能解释一下为什么static在函数体中和函数体外有着两种完全不同的意义吗?在函数体中,他表示“静态”——“在函数调用过程中保持这个变量唯一”。但是在函数体外,它的意义完全改变,成了“该变量为该文件私有的”。为什么后者不用
private或者
intern呢?
8. & 优先级低于 ==
在嵌入式编程中,我们总是喜欢用if ((x&MASK) == 0)这样的语句。但你可能常忘记写里面那对括号,因为感觉上,&的优先级应该比==高。但是事实并非如此,因此必须使用这对多出来的括号。
不过,这个情况有个不错的历史原因。C语言诞生自B语言,而在B语言中只有&而没有&&运算符。当Ritchie引入&&运算符时,他们希望原有的B语言端的代码能够正常运行,因此使&的优先级低于==。
C11 future:
vector<list<int>> i; // if not in C11 need a space between two closing template expressions vector<list<int>> i
相关文章推荐
- C++中构造函数和析构函数避免调用虚函数的问题
- C++ std lib study1
- 数值和字符串相互转换(C++ 数据类型转换技巧)
- C++test安装显示英文
- thrift框架使用C++
- 【转】C++ string CString详解
- Welcome Back to C++ (Modern C++)
- 全面介绍Windows内存管理机制及C++内存分配实例(五):堆
- 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
- C++面向对象程序设计的一些知识点(4)
- 全面介绍Windows内存管理机制及C++内存分配实例(二):内存状态查询
- CString,string,char[]的相互转换(vs2010c++验证无误)
- DirectShow9.0b在VC++6.0中环境设置+opencv
- 全面介绍Windows内存管理机制及C++内存分配实例(一):进程空间
- C++中const用法总结
- [转]深入理解C/C++ [Deep C (and C++)]
- iOS开发篇——C++输入与输出 推荐
- 你猜猜
- C++:文本分类器
- C++虚函数与虚函数表(四)