Function template summary

Function template

Basic example understanding function template

(1) Background:
In terms of adding two numbers, if the two numbers are of integer type, then we may have to write a function like the following,

 int add(int i,int j)
 {
    
    
        return i+j;
 } 

And if the two numbers are of floating-point type, then the function may be written like this,

float add(float i,float j)
{
    
    
      return i+j;
}

(2) Solution: Is there any way to optimize it? Yes, in order to reduce the redundancy of the code, the function template appears.
(3) Understanding of the function template:
3.1 can be understood as a function family
3.2 can also be understood as a formula
(4) Introduction to the function template syntax:

template<模板参数列表> 
函数返回类型 函数名(模板参数列表 形参名)
{
    
    
	 //......
 }

E.g:

 template<typename T>
T sub(T a, T b)
{
    
    
	return a + b;
}	

4.1 The definition of a template starts with the template keyword.
4.2 The type template is decorated with typename in front of it. Therefore, when you encounter typename, you will know that it is followed by a type, and typename can be replaced by class, but class here does not represent a class meaning,

template<class T>
T sub(T a, T b)
{
    
    
	return a + b;
}
//可以用class是由于历史原因,但是,还是尽量使用typename,并且,不能用struct。

4.3 The type template parameter T represents a type, which means that other identifiers can be used, such as U, etc.
The name 4.4T can be replaced with any other identifier, which has no effect on the programmer. Using T is just a habit.
(5) Demo

namespace _namesp1
{
    
    
	//template<typename T>
	template<class T>
	T sub(T a, T b)
	{
    
    
		return a + b;
	}
}
int sum = _namesp1::sub(1, 2); //根据1和2推断出T为int类型
cout << sum << endl;

double sum1 = _namesp1::sub(1.2, 3.4); //根据1.2和3.4可以推断出T为double类型
cout << sum1 << endl;

_namesp1::sub(1, 2.5);//不可以,矛盾了。编译器无法推断出T到底是int类型还是double类型。

Function template instantiation

Instantiation: When compiling, the process of replacing the type template parameter type with a specific "type" is called instantiation (some people call it a code generator). The
obj file can be generated after compilation. Check the obj file to see the specific instantiation. Future function.
In the VS development environment, you can use the dumpbin tool to view the obj file, so that you can see the actual function prototype. (common object file format--common object file format)

For example, when we write the following lines of code, the compiler will instantiate two function versions, and the function version can view the object file.

_namesp1::sub(1, 2);
_namesp1::sub(1.1, 2.2);

//The following is the specific content displayed by viewing the obj file:
the function names after instantiation are: sub and sub, and they are not called sub anymore.

//The function generated by the compiler according to the actual situation is as follows:

int __cdecl sub<int>(int,int)
double __cdecl sub<double>(double,double)

After instantiation, the function name consists of three parts,
(1) the template name
(2) <> angle brackets
(3) and the specific type
in the <> angle brackets. During compilation, the compiler will look at the function body part of the function template to Determine whether the instantiation process of the function template can be generated.
Summary: So when writing code such as function templates, the compiler will do two things. The
first thing is: before instantiation, the compiler will check whether the syntax is correct, such as whether it misses a semicolon and so on.
The second thing: During the instantiation, the compiler will also check to see if the instantiation is valid.

//Note: The instantiation process of a function template is to generate a different entity from the template, not a single entity that can handle any type, at least not now, maybe in the future.

Type inference for template functions

namespace _namesp3
{
    
    
	template<typename T,typename U>
	auto add(T i, U j)
	{
    
    
		cout << "auto add(T i, U j)" << endl;
		return i + j;
	}
	auto add(int i,int j)
	{
    
    
		cout << "auto add(int i,int j)" << endl;
		return i + j;
	}
}
  • Automatic inference
cout << _namesp3::add(1, 8) << endl;//根据1和8的值自动推断T和U为int类型
  • Show designation
(2)显示指定
cout << _namesp3::add<int,int>(1, 18) << endl;//显示指定T和U为int类型
cout << _namesp3::add<double,double>(1, 8) << endl;//T和U为double类型
cout << _namesp3::add<int,double>(1, 8) << endl;
  • Empty template parameter inference
(3)空模板参数推断要求编译器调用函数模板而非普通函数。
cout << _namesp3::add<>(1, 8) << endl; 
<>代表空类型模板参数,如果没有<>,那么就会调用非类型模板参数,这和编译器的调用优先级有关,如果我们想调用函数模板实例化的函数版本,那么可以加上<>

Function template overloading

Four: Function template overloading (the function name is the same, but the function return type or parameter type, or the number of function parameters is different)
4.1: The function (function template) has the same name, but the number or types of parameters are different
4.2: Function template and function Can exist at the same time, at this time the function can be regarded as an overload.
4.3: The compiler will give priority to calling ordinary functions instead of function templates.

Specialized

Regarding the understanding of specialization, let's first look at an example to illustrate what specialization is and why it is necessary.
Specialization of function templates:

template <class T>
T max(const T t1, const T t2)
{
    
    
  return t1 < t2 ? t2 : t1;
}

As mentioned above, the existing template definition may work abnormally for a pointer type parameter. When it is specific to the string pointer type, the following special template definition may be required:

template < >
const char* max(const char* t1,const char* t2)
{
    
    
  return (strcmp(t1,t2) < 0) ? t2 : t1;
}

So as to make the max ( "aaa", "bbb "); call more satisfactory (usually no one wants to compare the size of the address stored in two constant string)
Summary:

  1. The specialization of the template is a template implemented specifically for these special type parameters when the existing general templates are no longer suitable for some special type parameters.
  2. Partial specialization of a template refers to the need to specialize according to some parameters of the template.
  3. The rule of function call matching is: first exactly match the type parameter, then match the function template, and finally match through the parameter implicit type conversion
    4. Function templates cannot be partial specialization, but can be solved by function template overloading or function overloading
  • Generalization
namespace _namesp5
{
    
    
	template <typename T,typename U>
	void add(T i, U j)
	{
    
    
		cout << "泛化版本" << endl;
     	cout << i << endl;
		cout << j << endl;
	}
}
//普通的方式就是泛化版本,即,常规化,大众化。
  • All specialization
	//T = double U = double
	template<>
	//void add<double,double>(double i, double j)
	void add(int i, double j)
	{
    
    
		cout << "函数模板全特化" << endl;
		cout << i + j << endl;
	}
  • Biased specialization
	//偏特化编译失败
	//template<typename T>
	//void add<T,int>(T i, int j)
	//{
    
    
	//	cout << "函数模板偏特化" << endl;
	//  cout << i + j << endl;
	//}

//函数模板没有偏特化

Summary: The generalization and specialization of function templates are generally written in the .h file, and there is a generalized version first, and then a specific specialized version can be made according to the generalized version.

Function template default parameters

namespace _namesp6
{
    
    
	void add1(int i, int j)
	{
    
    
		cout << i + j << endl;
	}
	typedef void(*func1)(int, int);
	template<typename T,typename U,typename K = func1>
	void sub(T a, U b, K func1 = add1)
	{
    
    
		func1(a, b);
	}
	void add2(double i, double j)
	{
    
    
		cout << i + j << endl;
	}
	typedef void(*func2)(double, double);
	template<typename K = func2,typename T, typename U>
	void sub1(T a, U b, K gg = add2)
	{
    
    
		gg(a, b);
	}
}

Default parameters:
6.1 You can specify the type parameters of the function template.
6.2 If the first parameter of the type parameter is the default type, then all the following parameters do not have to be the default type, which is different from the class template.

_namesp6::sub(1, 2);
_namesp6::sub1(1.5, 2.7);

Non-type template parameters

  • basic concepts
namespace _namesp7
{
    
    
	//template <typename T,typename U,int value = 100>
	template <typename T, typename U, typename int value = 100> //int 前面的typename画蛇添足,但是语法没毛病(typename用来修饰后面是一个类型)
	//template <typename T, typename U, class int value = 100> //class 不行
	auto add(T i,U j)
	{
    
    
		return i + j + value;
	}	
	//template <typename T,int value>
	template <typename , int >
	auto fun()
	{
    
    
		return 100;
	}
}
 cout << _namesp7::add<int,int,10>(1, 5) << endl;
 cout << _namesp7::add(1, 5) << endl;

//非类型模板参数,也就是说,除了有类型以外,还可以有非类型的参数,例如值等等。

Note: Some limitations of non-type template parameters: floating-point numbers, class types, etc. These are historical reasons and may be supported in the future. Non-type template parameters are required to be constant, because the compiler needs to know the values ​​related to the function template at compile time.

  • Strange syntax
    a): Whether it is a type parameter or a non-type template parameter, if it is not used in the code, it can be omitted
cout << _namesp7::fun<int ,10>() << endl;
    b):类型前面可以增加一个typename修饰以明确标识一个类型

Guess you like

Origin blog.csdn.net/qq_38158479/article/details/113916321