C++ template programming in detail

  • 2020-11-20 06:10:51
  • OfStack

Type template

Type templates include function templates and class templates, and are basically the starting point for C++ developers to approach template programming.

The following code demonstrates the use of function templates and class templates:


//  A function template 
template<typename T>
T add(const T& a, const T& b) {
 return a + b;
}

//  Class template 
template<typename T>
class Point {
private:
 T x[3];
 ...
};

Type template with template Start declaration, Angle bracket typename Keywords available class Alternative. Type template typename and class With the same meaning, both represent parameter types. In the practice of typename The semantics are broader, representing its subsequent parameters T Is 1 type, not limited to classes, recommended. Type parameters T Can be replaced by any other meaningful legal variables.

C++14 New variable template:


//  Variable template 
template<tyepename T>
constexpr T pi = T(3.1415926535897932385L);

Angle brackets are to templates what brackets are to functions: functions are defined and called by brackets (), and templates use Angle brackets < > Definition (template keyword declaration required) and instantiation. The type template definition is demonstrated above, and the following code describes template instantiation:


int a = 1, b = 2;
//  Instantiate the function template 
std::cout << "add result:" << add<int>(a, b) << std::endl;

//  Instantiate the class template 
auto p = Point<int>();

double radius = .5;
//  Instantiate the variable template 
auto area = pi<double> * radius * radius;

Like function 1, a template can have default values:


//  The default type is int
template<typename T=int>
T add(const T& a, const T& b) {
 return a + b;
}

//  The default type is double
template<typename T=double>
class Point {
private:
 T x[3];
 ...
};

Unlike functions, for function templates, the Angle bracket template instantiation parameters can be omitted if the template type can be inferred from the parameters:


int a = 1, b = 2;
//  Legitimate calls, the compiler can be based on a b Infer the parameter type 
std::cout << "add result:" << add(a, b) << std::endl;
//  Is equivalent to 
std::cout << "add result:" << add<int>(a, b) << std::endl;

For class templates, however, you cannot omit Angle brackets, even if there are default parameters (but you can omit parameters) :


template<typename T=double>
struct Point {
 T x[3];
};

//  Legal statement 
auto p = Point<double>();
//  Legal declaration, the type USES the default double
auto p2 = Point<>();
//  Invalid declaration, missing template call flag Angle bracket 
auto p3 = Point();

Type parameter templates are most commonly used in practice. Many of the algorithms in STL library, vector, map and other containers, algorithm, use templates.

Non-type parameter templates

Another common type of template is a non-parametric template that replaces a specific value. Such as:


// N Dimensional space vector 
template<int N>
struct Vector {
 double x[N];
};

//  instantiation 
auto v = Vector<100>();
... Other operating 

It is important to note that there are a limited number of types available for non-typed parameter templates, with only (signed/unsigned) integers, char, and enumerations available (see. switch Syntax).

Like template 1, non-typed parameter templates can also have default values, but the Angle brackets cannot be omitted when applied to class template instantiation.

Type templates and non-type parameter templates can be used in combination with 1:


template<typename T, int N>
struct Point {
 T x[N];
};

The type template solves the problem of type, and the non-type parameter template solves the problem of value. It is also widely used in practice. As a classic scenario for recursion, Fibonacci Numbers can be solved using non-type templates:


template<int N>
struct Fib {
 static constexpr int value = Fib<N-1>::value + Fib<N-2>::value;
};
//  A template specialization 
template<>
struct Fib<1> {
 static constexpr int value = 1;
};
//  A template specialization 
template<>
struct Fib<0> {
 static constexpr int value = 0;
};

//  call 
std::cout << "Fib(10): " << Fib<10>::value << std::endl;

This is an example of "template specialization," which follows.

Template specialization/partial specialization

Once you define a template, you want to use a separate template under certain conditions. This is called template specialization. template as defined in the Fibonacci sequence above < int N > struct Fib is the master template, which then defines two more specialized templates (subtemplates), 0 and 1, indicating that the compiler has encountered Fib < 0 > And Fib < 1 > Use these two sets of separate definitions. Note that the template parameter for the specialized template is empty, and the specific template parameter is placed at the template name, similar to template instantiation.

In the case of multiple template parameters, if only one template parameter is specialized, it is partial specialization. Such as:


//  Generic template definitions 
template<typename T1, typename T2> struct Add; 
//  Specialized template 
template<> struct Add<int, int> {...};
//  Partial specialization template 
template<typename T> struct Add<T, long> {....};

Template specialization/partial specialization is similar to function overloading and can be tailored to a particular situation.

The template matches SFINAE

Template specialization allows multiple definitions of the same template name, and code calls may encounter template matching problems. The key to understanding the template matching mechanism is SFINAE, which is a prerequisite for advanced template programming.

SFINAE is short for Substitution failure is not an error, which translates as: failure to match (replace) is not an error.

What do you make of that?

For the Fibonacci sequence sequence code above, the compiler encounters Fib < 10 > ::value code, which (possibly) first tries to match Fib < 0 > , it found that the match did not match, it was 1 Substitution failure, but it was not error, so the compiler continued to try other possibilities. Then match Fib < 1 > , again find no match, ignore this Substitution failure and continue to try Fib < N > , OK, this time no problem, compile successfully.

If it is Fib < -1 > ::value, the compiler reached the maximum recursive depth and could not find a suitable matching template, this is 1 error, so the compilation failed.

[

Note: Understanding the above requires a little bit of understanding of the compilation process, which outputs a lot of information. Compiler 1 generally terminates the compilation only when error is encountered, and the more common warning does not. Substitution in a template match may not even count as warning and will not affect the compiler's ability to continue trying to match

]

Understanding SFINAE is the basics of understanding slightly more esoteric template code. The point is: You're afraid of having too many templates, but you can't find the right one.

Two-stage compilation

With template (meta) programming, C++ source code compilation can be divided into early and late, consisting of two stages of compilation. The early stage is the world of templates, the compiler scans the template instantiation statement, generates the operation result and the concrete code; The late compiler intervenes, then compiles to generate machine code.

The template code runs at compile time, so it has the following characteristics:

There is no instantiated template code, and the compiler does not check and report errors even if there are syntax errors. For C++ code farmers who check KPI according to the number of lines of code, this is definitely a blessing. Adding 100,000 lines of template code can be made up or written randomly. As long as it is not instantiated, it can always be compiled and passed, and the compiled file size (like 1) will not affect the operation of existing code. For constants, it is calculated directly in the early stage of compilation, with no runtime overhead. The Fibonacci Numbers above were calculated at compile time;
Code cannot be invoked dynamically at runtime. For example, the following requirements cannot be done:

//  Variable template 
template<tyepename T>
constexpr T pi = T(3.1415926535897932385L);
0 Templates and polymorphic/virtual functions (concepts) conflict. The key to polymorphic/virtual functions is the dynamic invocation of code at run time, while templates are determined at compile time, so the two concepts are in conflict. So, if you want to have a member function that is both a template function and a virtual function, how do you do that?
[

C/C++ compilation has a preprocessing process, which is just a simple string replacement, no concrete operation, and is different from template generation code

]

At the early stage of compilation, all code information is present except the template code is interpreted and executed, so the template code has a reflective/introspective ability, which is one of the reasons why C++ metaprogramming is so powerful.

Changes in C++11

C++11 has many new features and significant updates, and you can think of C++11 as a new language. In terms of templates, the main update points are as follows:

1. static constexpr int can be used instead of enum in the earlier template code. Many of the Fibonacci Numbers on the web are based on the early C++, law 1 USES enum to define fields.

2. It can be used using Instead of typename0 . This is a major update to the using statement capability, which we needed earlier to define types or aliases typename0 , C++11, simple to use using You get the same effect.

3. C++14 introduced the variable template, as described above.

Advantages and disadvantages of templates

Above, based on my own understanding and practice, I briefly introduced the relevant concepts of C++ template programming. This section summarizes the advantages and disadvantages of C++ templates under 1:

C++ Template programming Advantages:

Reduce code input, improve code reuse and programming efficiency; Support duck type (Duck typing) features, easy to use, powerful functions; In some cases, it can reduce the run-time overhead; Can realize metaprogramming, C++ master necessary road;

Disadvantages of C++ Template programming:

The syntax looks like hack black technology, the code is readable and tedious to write; The template code is difficult to debug and the error messages generated are hard to understand. Can you remember the horrible prompts for data types such as map, which were first used with the STL template? Compile time increases.

Thanks for reading and welcome to correct me!

The above is a detailed explanation of C++ template programming content, more about C++ template programming information please pay attention to other related articles on this site!


Related articles: