"In-depth practice C ++ template programming" of the three - Detailed template parameter types

Non-type template parameters and template-type template parameters
Integer and enumerated types; pointer to object or function; reference object or function; pointer to object members. Collectively referred to as non-type template parameters.
Template template parameter type, refer to template parameters may also be a template.
 
1, the integer template parameter
The role of non-type template parameters corresponds to a function template or class of templates predefined constants, in generating template instance, also required to be known at compile i.e. the value assigned to the non-constant-type template parameters. // is a template parameter, but it is not a template parameter, and will not fit different types, but some type of fixed so his advantage in what? "Constant template declared, in all instances templates have the same value, rather than the type of template parameters have different values for different instances of templates to meet different needs." This saying too official, and we look at an example:
template<typename T>
class CArray
{
static cosnt unsigned size = 10;
T elems[size];
public:
T& operator[](unsigned i) throw (std::out_of_range)
{
if (i >= size)
{
throw std::out_of_range("Access out of range\n");
}
else
{
return elems[i];
}
}
};

 

What is wrong with this example? The problem is that the size of the array is written dead, this template can only flexible adaptation of different array types in the compiler, but can not fit different size of the array. But if you end up with this it would be much flexibility:
 1 template<typename T, unsigned Size>
 2 class CArray2
 3 {
 4 T elems[Size];
 5 public:
 6 T& operator[](unsigned i) throw (std::out_of_range)
 7 {
 8 if (i >= size)
 9 {
10 throw std::out_of_range("Access out of range\n");
11 }
12 else
13 {
14 return elems[i];
15 }
16 }
17 };

 

Let's verify, different values ​​of non-type template parameters Size, whether generated by a different function instance, slightly modified at the function as follows:
 
template<typename T, unsigned Size>
class CArray2
{
public:
CArray2()
{
id++;
}
~CArray2(){}
 
T elems[Size];
public:
T& operator[](unsigned i) throw (std::out_of_range)
{
if (i >= size)
{
throw std::out_of_range("Access out of range\n");
}
else
{
return elems[i];
}
}
 
public:
static int the above mentioned id; 
}; 
 
Template <typename T, unsigned Size> int CArray2 <T, Size> :: the above mentioned id = 0 ; // the way, we should also understand how this template class with non-type template parameters to define a static member of the 
 
void main () 
{ 
CArray2 < char , 20 is > ARRAY0; 
the printf ( " ID:% D \ n- " , array0.id); 
 
CArray2 < char , 20 is > array1; 
the printf ( " ID:% D \ n- " , array1.id ); 
 
CArray2 < int , 10 > at array3; 
the printf ("ID:%d\n", array3.id);
 
CArray2<int, 20> array4;
printf("ID:%d\n", array4.id);
 
getchar();
}
 

 

Results are as follows:

 

 

 
2, function pointer template parameters
The previous section, wrote in a fixed template parameters died a data type, here we can also write to die some fixed function parameter type when defining template. And this type of function parameters and can be adapted to the type of template template parameter.
 
 1 template<typename T, void(*f)(T &v)>
 2 void foreach(T array[], unsigned size)
 3 {
 4 for (unsigned i = 0; i < size; ++i)
 5 {
 6 f(array[i]);
 7 }
 8 }
 9  
10 template<typename T>
11 void inc(T &v){ ++v; }
12  
13 template<typename T>
14 void dec(T &v){ --v; }
15  
16 template<typename T>
17 void print(T &v){ printf("%d ", v); }
18  
19 void main()
20 {
21 int array[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
22 foreach<int, print<int>>(array, 8);
23  
24 foreach<int, inc<int>>(array, 8);
25  
26 getchar();
27 }
 
3、指针及引用模板参数
只有指向全局变量及外部变量及类静态变量的指针及引用才可以作为模板参数。函数的局部变量、类成员变量等均不能作为模板参数。因为模板参数值必须是编译时已知的。
 
 1 template<int* p>
 2 struct wrapper
 3 {
 4 int get(){ return *p; }
 5 void set(int v){ *p = v; }
 6  
 7 };
 8  
 9 template<int &p>
10 struct wrapper2
11 {
12 int get(){ return p; }
13 void set(int v){ p = v; }
14 };
15  
16 int global_variable = 0;
17  
18 int main()
19 {
20 wrapper<&global_variable> gwrapper;
21 wrapper2<global_variable> gwrapper2;
22 }

 

有一个明确的结论是,global_variable 决定了gwrapper的类型。即如果我添加一个
int global_variable3 = 0; 和 wrapper<global_variable3> gwrapper3;
那么gwrapper和gwrapper3并非同一个类型。
之前我们讲述的是用typename T来区分两个模板实例,但是这里的一个指针、一个整形常量(统称非模板型模板参数)就可以直接区分模板实例:
 1 template<int* p>
 2 struct wrapper
 3 {
 4 public:
 5 wrapper(){ id++; }
 6 int get(){ return *p; }
 7 void set(int v){ *p = v; }
 8 public:
 9 static int id;
10 };
11 template<int* p> int wrapper<p>::id = 0;
12  
13 int global_variable = 0;
14 int global_variable3 = 0;
15  
16 int main()
17 {
18 wrapper<&global_variable> gwrapper;
19 printf("ID:%d\n", gwrapper.id);
20  
21 wrapper<&global_variable> gwrapper4;
22 printf("ID:%d\n", gwrapper4.id);
23  
24 wrapper<&global_variable3> gwrapper3;
25 printf("ID:%d\n", gwrapper3.id);
26  
27 getchar();
28  
29 }

 

4、成员函数指针模板参数
 
class some_value
{
int value;
public:
some_value(int _value) :value(_value){}
int add_by(int op){ return value += op; }
int sub_by(int op){ return value -= op; }
int mul_by(int op){ return value *= op; }
};
 
typedef int (some_value::* some_value_mfp)(int);
 
template<some_value_mfp func>
int call(some_value &value, int op){ return (value.*func)(op); }//*是必要的,否则会认为是在使用value类的成员func
 
void main()
{
some_value v0(0);
printf("%d\n", call<&some_value::add_by>(v0, 1));//&是必要的,否则会认为是调用some_value::add_by但是没给参数
printf("%d\n", call<&some_value::sub_by>(v0, 2));
printf("%d\n", call<&some_value::mul_by>(v0, 3));
getchar();
}
 
 
5、模板型模板参数
首先我有三个模板:
template<typename T>
struct inc
{
void operator()(T &v) const { ++v; }
};
 
template<typename T>
struct dec
{
void operator()(T &v) const { --v; }
};
 
template<typename T>
struct print
{
void operator()(T &v) const { std::cout << ' ' << v; }
};
 
这三个模板决定了foreach生成不同的实例(当然还有foreach本身的第二个模板参数),这里注意只有类模板可以作为模板参数,所以这里只能用class而不能用struct:
template<template<typename TT> class Func, typename T>
void foreach(T array[], unsigned size)
{
Func<T> func;
for (unsigned i = 0; i < size; i++)
{
func(array[i]);
}
}

 

在foreach中使用第一个模板 or 在foreach中使用第二个模板 or 在foreach中使用第三个模板?都有可能!所以要在foreach中添加一个模板参数用来决定使用哪个模板,这就是模板的模板,也就是模板型模板参数。
void main()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7 };
foreach<print>(array, 7);
foreach<inc>(array, 7);
foreach<dec>(array, 7);
 
getchar();
}

 


 
 

 

Guess you like

Origin www.cnblogs.com/predator-wang/p/11479668.html