您的位置:首页 > 编程语言 > C语言/C++

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
(&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
sizeof
on
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: