Template specialization and type extraction

Posted by BoltZ on Thu, 20 Jan 2022 20:22:23 +0100

1, Purpose and significance of type extraction

1. Type extraction is the purpose

(1) A typical application is to distinguish whether T is a source generated type POD or a user-defined type in the template function

(2)POD,Plain Old Data, is simply understood as the basic types inherited from C by C + +, such as int, double, etc

(3) The essence of pod type is those high-level features without C + + superposition (construction, deconstruction, copy construction, mobile semantics, virtual functions, etc.)

2. Why distinguish between POD type and non POD type

(1) A typical case is copy. The POD type can be directly memcpy (a library function of C language), while the non POD type needs to be copied one by one with a for loop combined with "=" (the overloaded = operator provided by default can realize object copy)

(2) Non POD types cannot memcpy (involving dynamic memory), because deep copy is required to avoid errors

(3) Code drill: copy comparison of int array and string array

#include <iostream>
#Include < CString > / / the string of C language H header file
#Include < string > / / the string header file of C + +, which is different from the one above

using namespace std;

template <typename T>
void mycopy(T* Dst, T* Src, int count)
{
    memcpy(Dst, Src, count);
}

int main(int argc, char *argv[])
{
#if 0    
    int a[3] = {1, 2, 3}, b[3] = {0};
#else

    string a[3] = {"linux", "android", "harmonyos"};
    string b[3];

    
    for(int i = 0; i < 3; i++)
    {
        cout << a[i] << ' ';
    }
    cout << endl;
 
    mycopy<string>(b, a, sizeof(string)*3);//Although it can be executed, an error will be reported. This is a shallow copy
    a[1] = "ubuntu";                       //Error message: free(): invalid size, abandoned (core dumped)
 
    //mycopy<int>(b, a, sizeof(int)*3);
    //a[0] = 0;

    for(int j = 0; j < 3; j++)
    {
        cout << a[j] << ' ';
    }
    cout << endl;

    for(int k = 0; k < 3; k++)
    {
        cout << b[k] << ' ';
    }
    cout << endl;

#endif
    return 0;
}

2, Type extraction practice

1. Use is_pod solves the above problems

(1)std::is_ Introduction to pod

//Use example
#include <iostream>
#include <type_traits>
 
struct A {
    int m;
};
 
struct B {
    int m1;
private:
    int m2;
};
 
struct C {
    virtual void foo();
};
 
int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_pod<A>::value << '\n';
    std::cout << std::is_pod<B>::value << '\n';
    std::cout << std::is_pod<C>::value << '\n';
}

Output:
true
false
false

(2) Code practice, using is_pod to improve mycopy and solve the problems in the previous section

#include <iostream>
#include <string>
#include <cstring>

using namespace std;

template <typename T>
void mycopy(T* Dst, T* Src, int count)
{
    if (is_pod<T>::value)
    {
        memcpy(Dst, Src, sizeof(T)*count);
    }
    else
    {
        for(auto i = 0; i < count; i++)
        {
            Dst[i] = Src[i];
        }
    }
}

int main(int argc, char *argv[])
{
    string a[3] = {"linux", "android", "harmonyos"};
    string b[3];

    for(int i = 0; i < 3; i++)
    {
        cout << a[i] << ' ';
    }
    cout << endl;
 
    mycopy<string>(b, a, 3);
    a[1] = "ubuntu";

    for(int j = 0; j < 3; j++)
    {
        cout << a[j] << ' ';
    }
    cout << endl;

    for(int k = 0; k < 3; k++)
    {
        cout << b[k] << ' ';
    }
    cout << endl;

    return 0;
}

2. Other types of extraction provided by std

Simple old data type (PODType), which is both ordinary and standard layout:

3, How is type extraction implemented

1. A possible implementation (method 1)

(1) Make a list of all pod types, judge one by one internally, and use two keywords:

typeid The type used to return a variable (expression) (object), similar to C Language: typeof() 
yes GUN C Provides a feature that can obtain the type of a variable or the type of an expression.

(2) Advantages: it can be realized, and < type_ All standard library extraction tools in traits >

(3) Disadvantages: runtime judgment, occupying runtime resources and low efficiency

2. Special implementation using class template (method 2)

(1) Code practice demonstration

#include <iostream>
#include <cstring>
#include <string>

using namespace std;


// Generalized version of my_is_pod
template<typename T>
struct my_is_pod
{
	static bool value;
};

template<typename T>
bool my_is_pod<T>::value = false;


// Specialized version of int type
template<>
struct my_is_pod<int>
{
	static bool value;
};
bool my_is_pod<int>::value = true;

// A specialized version of the double type
template<>
struct my_is_pod<double>
{
	static bool value;
};
bool my_is_pod<double>::value = true;

// Specialized version of short type
template<>
struct my_is_pod<short>
{
	static bool value;
};
bool my_is_pod<short>::value = true;

//Using this method for string type will also report errors. I tried, but I didn't study it in depth

template<typename T>
void mycopy(T *dest, const T *src, int cnt)
{
	// We need a technique here to distinguish whether T is pod or non pod
	if (my_is_pod<T>::value)
	{
		cout << "if" << endl;
		memcpy(dest, src, cnt*sizeof(T));
	}
	else
	{
		cout << "else" << endl;
		for (int i=0; i<cnt; i++)
		{
			dest[i] = src[i];			// Non pod types can be replicated using operator =
		}
	}
}


int main(void)
{
//	cout << boolalpha << my_is_pod<double>::value << endl;

	short a[3] = {4, 5, 6};
	short b[3] = {0};
	
	mycopy<short>(b, a, 3);
	for(int i=0; i<3; i++)
		cout << b[i] << "   ";
	cout << endl;

/*	
	string s1[3] = {"linux", "android", "harmonyos"};
	string s2[3];
	
	mycopy<string>(s2, s1, 3);			// Non pod types cannot memcpy because shallow copy will cause errors

	for (int i=0; i<3; i++)
	{
		cout << "s2[" << i << "] = " << s2[i] << endl;
	}
	
	s1[0] = "abc";
	cout << "last, s2[0] = " << s2[0] << endl;
*/	
	
	return 0;
}

(2) Conclusion: the key to the extraction of specialization is that the priority of specialization version is higher than that of generalization version

(3) Thinking: will the use of class template specialization increase the amount of code and affect the program efficiency?
  it will increase the amount of code and will not affect the efficiency. Template specialization is judged at compile time.

4, Another possible implementation of type extraction

1. Do not use static member variables
2. Use member functions instead
3. Use typedef to add an intermediate layer
(1) Methods of defining subtypes using typedef in class / struct
(2) Add a name called value_ The subtype middle layer of type realizes pod judgment

#include <iostream>
#include <cstring>
#include <string>

using namespace std;

struct FalseType
{ 
	bool GetType()
	{
		return false;
	}	
};

struct TrueType
{ 
	bool GetType()
	{
		return true;
	}	
};

// Generalized version of my_is_pod
template<typename T>
struct my_is_pod
{
    typedef FalseType value_type;
};


template <>
struct my_is_pod<short>
{
    typedef TrueType value_type;
};

int main(void)
{
    cout << boolalpha << my_is_pod<int>::value_type().GetType() << endl;//value_ This () of type () represents the constructor
	return 0;
}

5, Iterator extraction and generic algorithm

1. The core of STL

(1)STL is a set of template d libraries provided by C + +

(2)STL has many contents, but the core is two: generic container and generic algorithm

(3) In order to implement generic containers, iterators are introduced, which are generalized abstractions of pointers

(4) Generic algorithms can accept multiple containers, and each container can store multiple data carriers, which is the level 2 generalization support of generic algorithms

2. Problems and solutions of generic algorithm implementation

(1) Problem 1: generic algorithms cannot predict what containers they are dealing with

Solution: demote the container to an iterator to dock the generic algorithm. So any container must have an iterator built in

(3) Question 2: the generic algorithm cannot predict the element type stored in the container. Is it POD

Solution: provide iterator extractor, pre extract and use container element type in generic algorithm

6, Design and interpretation of iterator extractor

(1) Iterator extractor is essentially a class called iterator_traits, a third-party class of auxiliary iterators

(2) Interpretation reference: https://blog.csdn.net/virtual_func/article/details/48398451

7, Specialization of iterator extractor

1. Special explanation of extractor

(1) Reference: https://blog.csdn.net/terence1212/article/details/52287762

(2) Summary: the essence is partial specialization combined with type extraction technology

2. Summary of this chapter

(1) Two technologies are mainly discussed, one is specialization and the other is extraction

(2) The core value of specialization is to match template classes / functions according to certain priority rules

(3) The core value of extraction is that we can know in advance the type characteristics of the future reference container and the elements in the container when writing the generic algorithm

(4) If you only use STL, you don't need to pay attention to specialization and extraction

(5) If you really understand the use and implementation of template technology, specialization, extraction and other technologies, you will feel the charm of C + + and know why C + + is efficient

(6) From a practical point of view, there is no need to study these in real depth. But if you don't understand or even know the existence of these technologies, you can't make good use of C++

Note: This article refers to the course notes of Mr. Zhu's Internet of things lecture hall, combined with his own actual development experience and the technical articles of others on the Internet. If there is infringement, contact to delete! Limited level, welcome to communicate in the comment area.

Topics: C++ data structure STL