C+++ Template Advancement

Posted by Ton Wibier on Mon, 05 Aug 2019 10:25:24 +0200

Template Advancement

Untyped parameter template

Template parameter classification type shape participates in untyped parameter classification.
Type parameters are: they appear in the template parameter list, followed by parameter type names such as class or typename.
Untyped parameter is a parameter of class (function) template, which can be used as a constant in class (function) template.

// Define a static array of template types
template<class T, size_t N = 10>
class Array
{
public:
	T& operator[](size_t index)
	{
		return _array[index];
	}
	const T& operator[](size_t index)const
	{
		return _array[index];
	}
	size_t Size()const
	{
		return _size;
	}
	bool Empty()const
	{
		return 0 == _size;
	}
private:
	T _array[N];
	size_t _size;
}
  1. Floating-point numbers, class objects, and strings are not allowed as untyped template parameters.
  2. Untyped template parameters must be validated at compile time.

Template specialization

concept

Typically, you can use templates to implement type-independent code, but for some special types you may get some wrong results
For example:

template<class T>
bool IsEqual(T& left, T& right)
{
	return left == right;
}
void Test()
{
	char* p1 = "world";
	char* p2 = "hello";
	
	if(IsEqual(p1, p2))
		cout<<p1<<endl;
	else
		cout<<p2<<endl;
	// Output hello
	// Because it's the address that's coming in.
	// Comparing address size with string size
}

Function template specialization

Specification steps for function templates:

  1. There must be a basic function template first.
  2. Keyword template followed by a pair of empty brackets <>
  3. Function names are followed by a pair of parentheses, in which the type to be specialized is specified
  4. Functional parametric table: Must be exactly the same as the basic parameter type of template function, if different compilers may report some strange errors.
template<>
bool IsEqual<char*>(char*& left, char*& right)
{
	if(strcmp(left, right) > 0)
		return true;
	return false;
}

// Normally, if a function template encounters a type that cannot be handled or that has been handled incorrectly,
// In order to achieve simplicity, this function is usually given directly.
bool IsEqual(char* left, char* right)
{
	if(strcmp(left, right) > 0)
		return true;
	return false;
}

Full Specialization

Full specialization means that all the parameters in the template parameter class table are determined.

template<class T1, class T2>
class Data
{
public:
	Data() {cout<<"Data<T1, T2>" <<endl;}
private:
	T1 _d1;
	T2 _d2;
};
template<>
class Data<int, char>
{
public:
	Data() {cout<<"Data<int, char>" <<endl;}
private:
	int _d1;
	char _d2;
};
void TestVector()
{
	Data<int, int> d1;
	Data<int, char> d2;
}

partial specialization

Partialization: Any special version that further restricts the design of template parameters. For example, for the following template classes:

template<class T1, class T2>
class Data
{
public:
	Data() {cout<<"Data<T1, T2>" <<endl;}
private:
	T1 _d1;
	T2 _d2;
};

There are two manifestations of partial specialization
partial specialization
Specialization of some of the parameters in the template parameter class table

// Specialize the second parameter to int
template <class T1>
class Data<T1, int>
{
public:
	Data() {cout<<"Data<T1, int>" <<endl;}
private:
	T1 _d1;
	int _d2;
};

Further constraints on parameters
Partialization is not only a partial parameter specialization, but a special version designed for further jump limitation of template parameters.

//Partialization of two parameters to pointer type
template <typename T1, typename T2>
class Data <T1*, T2*>
{
public:
	Data() {cout<<"Data<T1*, T2*>" <<endl;}
private:
	T1 _d1;
	T2 _d2;
};
template <typename T1, typename T2>
class Data <T1&, T2&>
{
public:
	Data(const T1& d1, const T2& d2)
	: _d1(d1)
	, _d2(d2)
	{
		cout<<"Data<T1&, T2&>" <<endl;
	}
private:
	const T1 & _d1;
	const T2 & _d2;
};
void test2 ()
{
	Data<double , int> d1; // Invoke the specialized int version
	Data<int , double> d2; // Call the underlying template
	Data<int *, int*> d3; // Call Specialized Pointer Version
	Data<int&, int&> d4(1, 2); // Call Specialized Pointer Version
}