Skip to playerSkip to main content
  • 18 minutes ago
Templates use types and values as parameters for creating classes, effectively specifying a family of classes from a single declaration. The type or value parameters are specified during object creation. https://www.softprayog.in/programming/templates-in-cpp
Transcript
00:00Hello and welcome to this video. I am Karnesh Jholy. This video is about
00:05templates in C++. C++ helps in expressing concepts like vector, list, map
00:15in code. These concepts are independent of data types of their elements. You can
00:23have a vector of doubles or strings or a user-defined type. Templates provide the
00:31facility for defining classes and functions with types as parameters. A
00:39single class or function template declaration can support a wide spectrum
00:46of types. This leads to compact and elegant software
00:52design. Let's look at templates in a little detail. The first topic under
00:58templates is parameterized types which is passing of type parameters in class
01:05declarations. This is the most common usage of templates. For example, here's a
01:12declaration of class template of vector of type T. T is the type parameter. The
01:20declaration starts with the keyword template and then type parameters come
01:26in angle brackets that is the less than and greater than symbols. Inside the angle
01:32brackets the keyword type name and then the type parameter which is T here. This is
01:40followed by the class declaration where we can use the parameter T for type in data
01:46numbers and methods. Using this class template, we can define vector objects of
01:53different types. For example, we can say vector int v1 5000 which is a vector of 5000
02:02ints. Similarly, we have more examples vector char vc 200, vector of 200 characters, vector std string
02:13v17, vector of 17 strings, vector std list int vli 45, vector of 45 lists of integers, vector std complex
02:27double vcp3, vector of 3 complex numbers. And this is an example program using a vector class template.
02:38First, the vector class template declaration. We use a parameter type T in private data
02:45members and also in the public methods. After the class template declaration, we
02:51have an addition operator overload function for adding two vectors. This is also a
02:57template. In fact, it is a function template where type T is a parameter. The two arguments to
03:05addition function are vectors of type T and so is the result. And in the main function, we define
03:12some vectors v0, v1, v2, etc. and do some assignment and addition operations. We can compile and run this
03:22program it works fine. In the previous example, we have seen a class template with type parameters.
03:35We can also have value parameters for class declarations. Suppose we wish to have a C style
03:42fixed size array, fixed array. It has two parameters, the type of element of array and the size of the array.
03:51So, we declare a class template fixed array with parameter type named T that is the type of elements
03:59and n which is the size of the array. And there are two constructors. The default constructor initializes
04:06elements to the default for the type of the element. The second constructor takes in an initializer list
04:13as an argument for initializing the array. And we have getWell function which returns an element
04:20for the given array index and a setWell function for setting an element with the given value well
04:28at the given index. And there is a print function for printing the array. In the main function,
04:34we define a fixed array with element type int and size 5. And we exercise the methods or in the fixed array
04:44class, it all works fine. We have seen templates for classes. Now let's look at functions. A function implements
04:58and algorithm which is an algorithm which is also a general concept applicable for multiple types. So,
05:05it is but natural that templates can be used for functions as well. We use the same notation as before.
05:12For example, to add two numbers, we say template type name t, t add t a t b return a plus b.
05:24This template has one parameter type t. The type is specified at the time of function call. It can be
05:32explicitly mentioned as in the first call add int ij or it can be implicit and is deduced from the
05:42arguments. As in the second call, add d e. In all template usage, the types are known at compile time
05:51and there are no runtime overheads. Another example of function templates. Here, we have a template
05:59with two type parameters c and t. c is the type for container and t is type for accumulator,
06:07which keeps the sum of elements of the container. We pass a reference to a container and the initial
06:15value of the sum. The function accumulate adds all the elements of container and returns the sum.
06:23We can call the accumulate function with reference to different containers and different types of
06:30sum variable. The next topic is function objects also known as functors. As the name function object
06:48suggests, it is an object of class and it is also a function. It is an object which can be called as a
06:56function. How does that happen? The underlying class implements the function call operator parenthesis.
07:04For example, we have a class which finds whether an argument is less than a fixed value, template type t,
07:13class less than constant t well. This is the value to compare against and the public members
07:20constructor constructor less than constant t reference v well initialize to v and the class implements the function call operator bool operator parenthesis constant t reference x constant
07:36return x is less than well. The key difference between functors and functions is that
07:43functors have state information in the form of data members which is not there in functions. For example,
07:51we have constant t well here the value to compare against. We can initialize objects of less than functor.
07:59The first is less than int 49 which has an integer 49 and the next is less than std string lts apricots
08:10which has a string with value apricots. We can use these functors in our program.
08:17Suppose we wish to count the number of elements in a container that meet the functor criteria,
08:25that is the elements for which the functor is true. We can do something like this.
08:31We have a function template count with two type parameters c and p. c is the type of container
08:39and p is a predicate a boolean expression that evaluates to false or true. We can use functor as a
08:48predicate. In the main function we have a vector of integers vi and we wish to know how many elements of vi
08:57are less than integer vi and functor less than integer i where i is 29. Similarly, we have a list of strings ls
09:12and we wish to know how many elements of ls are less than the string nectar. So we call count with
09:20container ls and functor less than string s which is nectar and count returns the number of elements of list
09:30less than nectar. In the preceding example, we have used functor as an argument to function count.
09:38It plays an important role in the way count works. We have used the functor template less than.
09:45We could have used a different functor like greater than, equal to, etc. and got the count function
09:53to work differently and give a different output. The point is that functors are often used as arguments
10:01to functions and they play an important role in the way the use function works. For example, here we use the
10:09std sort function for sorting vector v first in the descending order and then in the ascending order.
10:18Both descending and ascending are functors which are passed as arguments to the sort function.
10:25Back to our example, we have used a functor as a parameter to the count function. We set the functor state
10:34in the constructor. The functor state variables integer i in the first case and the string s in the second case.
10:43A lambda expression is a shortened notation for an anonymous functor call. Here we have replaced functors
10:52with lambda expression in the example code. Comparing the two, in case of functors, we need to create
11:00a functor using a constructor and then use it in a function like count. In case of lambda expressions,
11:09we can just put it in place where required and the job is done. In both cases, the code is inlined,
11:18so the overheads are minimal. Looking at a lambda expression, there are three distinct parts.
11:24The first is the capture list in square brackets. The second is an optional parameter list in parenthesis
11:33and the third is the body in braces, which is the lambda expression code to be executed. The capture
11:41list is for capturing the local variables in the function, similar to creating the state in functors.
11:48The rules for capturing local variables are like this. If the capture list is empty, nothing is captured.
11:56If there is just an ampersand in the capture list, all local variables are implicitly captured by reference.
12:05If there is just an equal sign in the capture list, all local variables are implicitly captured by value.
12:13If there is a capture list where variables are listed explicitly, only those listed are captured.
12:21Variables preceded with an ampersand are captured by reference and the others are captured by value.
12:29Ampersand comma capture list. Implicitly capture all variables by reference except those in the capture
12:38list which are captured by reference and these variables in the capture list must be preceded by an ampersand.
12:58Next, we have parameters with types in parenthesis. For each call of lambda expression, these parameters need to be passed.
13:08And finally, the body comprising of code which is executed when the control reaches the lambda expression.
13:21Variatic templates are templates that allow variable number of type parameters.
13:27That is template type name t, type name dot dot dot rest. The three dots after type name indicate that there are zero or more type parameters.
13:42And we can have a function template using a variadic template. That is template type name t, type name dot dot dot rest.
13:52The key to handling a variadic template is that the first type parameter is separated from the rest.
14:11As you can see, the definition of function f, there is t first, the first argument and the rest of arguments.
14:21We process the first argument in the function g, the call g first and then call the function f itself recursively with the rest of arguments.
14:32Eventually, there are no arguments left and function f is called with no arguments.
14:38To take care of that, we have a definition of function f with empty body that is void f braces and the recursion terminates.
14:47We have an example program using a variadic template and it is like this.
14:53First, we have a function template for function g which just prints the argument on the standard output.
15:00Then we have the empty function f for terminating the recursion and then the variadic function template.
15:07The function f calls function g with the first parameter which does the processing of one parameter and then function f calls itself with the rest of parameters.
15:19In the main function, we call function f with some random arguments and this is done twice.
15:25We can compile and run this program. It works fine.
15:33An alias is a different and more convenient name for something.
15:38In traditional C and C++, we have type def which is something like this.
15:44Type def unsigned int size t. This makes size t a synonym of unsigned int.
15:52We can define variable i of type size t. Actually, size t is not a new type.
15:58It is just a synonym for unsigned int and we can print its size using the size of operator.
16:05That's the old way of doing things.
16:07Starting with C++ 11, there is a better way of doing this and it is the using declaration.
16:15We can say using size u equal to unsigned int. That makes size u a synonym of unsigned int.
16:23Then we can define a variable j, size u j and we can use j in the code.
16:29Now consider this template. Template type name t class vector public using value type equal to t.
16:39Here value type is an alias for template parameter type t. It is an alias for type of elements of vector.
16:47The standard library follows this convention that value type gives the type of the elements of a
16:53standard library container. For container c, we can define a template alias using value type equal to
17:01type name c double colon value type. Then value type c gives the type of element of container c.
17:09Here is an example for template alias. We define value type as an alias for type name c double colon
17:18value type and the function template sum adds all the elements of container c and the result is stored
17:26in a variable of appropriate type which is the type of elements of the container. In the main function,
17:33we call sum with a vector of integers, vector of strings and a list of strings and it adds up all the elements.
17:42We have seen how templates help in declaring classes with type and value parameters. You can find all this
17:52information at SoftYoke website. Here is the QR code and the link is there in the description. Please
18:00subscribe to SoftYoke channel, click on the bell icon and enable notifications. Thanks very much for
18:07watching. Take care and stay safe.
Be the first to comment
Add your comment