Submind YouTube summaries
Thumbnail for C++ Templates Tutorial for Beginners

C++ Templates Tutorial for Beginners

Watch on YouTube

Video summary

C++ templates serve as a powerful mechanism for generic programming, enabling algorithms and classes to operate on any data type without the need to write separate functions for each specific type. Unlike function overloading, which becomes cumbersome when dealing with numerous types, templates allow the compiler to automatically generate specific function copies, known as instantiations, based on argument deduction at compile time. This process involves defining function templates using the `template` keyword and type placeholders like `typename T`, where the compiler infers the type from arguments unless explicit template arguments are provided or deduction fails. The tutorial also explores non-type template arguments, which use constant expressions such as array sizes to pass arrays by reference without explicitly specifying their dimensions, thereby streamlining code for scenarios involving fixed-size collections. Beyond basic function templates, the course delves into class templates used to create generic structures like stacks and vectors, highlighting that template parameters become an integral part of the class type itself. This distinction affects how member functions are defined outside the class, requiring full qualification with the scope resolution operator. The video further addresses explicit specialization, demonstrated through a `PrettyPrinter` class that requires custom implementations for specific types like `std::string` or `std::vector<int>` due to issues with pointer arithmetic or type resolution. While primary templates reside in header files, these specialized implementations must be defined in `.cpp` files to adhere to the One Definition Rule, ensuring that only necessary logic adjustments are made rather than rewriting entire class structures. The tutorial expands into advanced concepts such as variadic templates and partial specialization, showcasing how functions can accept a variable number of arguments using parameter packs and recursion. Implementations utilize base cases to terminate recursive calls and employ techniques like `sizeof` on the pack to manage separators, while perfect forwarding with `std::forward` preserves value categories during these operations. Partial specialization is illustrated by optimizing formatting for specific device widths using non-type template parameters and creating smart pointers that handle array types differently from single pointers by removing invalid operators in favor of subscripting. Additionally, the video clarifies the differences between traditional type definitions and C++11 type aliases, noting that only alias templates can be templatized to support complex generic contexts like nested vectors of lists. Finally, the discussion on type aliases emphasizes their ability to create synonyms for existing types within generic contexts where standard typedefs fall short, allowing for more flexible and reusable code designs. The comprehensive overview concludes by reinforcing how these tools collectively empower developers to write efficient, type-safe, and maintainable C++ code that adapts seamlessly to various data types and structural requirements. By mastering function templates, class templates, explicit and partial specializations, and variadic techniques, programmers can overcome the limitations of manual overloading and build robust software solutions that scale effectively across different application domains.
Read the full video transcript
hi welcome to this course on beginning c plus templates I'm Umar your host let me give you some background about myself I have a degree in civil engineering but I've always been passionate about programming this course is an excerpt from another course called beginning modern C plus plus I will give you a quick overview of what I'm going to teach in this course I'll introduce templates and then we'll move on to argument reduction template instantiation then we'll also look at the specialization of function and class templates I will also explain some common C plus 11 features such as veridik templates and Alias templates after this training is over you will be able to understand and interpret the complex syntax of templates and you will be able to write your own function and class templates thanks for checking out my course [Music] hi and welcome back in this video we'll learn about templates templates are used for generic programming that means you can write algorithms and classes without regards to the data type let's understand it with an example assume in our program we want to find the maximum value from two numbers so for this we'll create a function so the function name is Max it accepts two integers and will return the one that has the largest value so if x is greater than y then return X else return y and we can invoke this function from Main and we may also print it let's run it perfect if we also want to find the maximum value from two Floats or two doubles then we will have to write a function for each data type and obviously we can overload the max function for a specific data type so we can just replace int with float and it would also work for floating Point numbers and if we run this it shows the correct value if we want to use max to compare the larger value of some other types then we will have to overload the max function for each type and this is going to be tedious it will lead to large number of functions this is where templates can step in templates allow us to write a function that can operate on any kind of data type let's go ahead and convert this Max function into a function template any kind of template always begins with the keyword template then you have to specify the placeholder for the types and that is specified as type name and then you have to specify some name so we'll give the name as t now this T is the placeholder for the type and it will be automatically substituted by the compiler during compilation in some books you may see the keyword class being used instead of type name and in this context there is no difference between the usage of class and type name both declare a name that is used as a placeholder for the type the differences between the class and type name are apparent only when you do Advanced template programming but throughout our sessions I will use the keyword type name instead of class the return type will be t and the arguments are also going to be of type t now we don't need the function that we have implemented earlier so let me go ahead and comment them out our program will still work because the compiler will automatically substitute this t with the type of its argument so the argument types are floats so T will be of type float and that's not all we can also invoke this function for other types and if we run this so it shows the correct output so we did not have to write a function for each type instead the compiler will automatically generate the function for the appropriate type the compiler will examine the arguments of the function calls and accordingly will deduce the type of t so in this case the type of T is deduced as float and the second function call of Max where we pass the integers the type of T is deduced as int that is why compiler will generate two copies of Max function one copy will be for float and other will be for the integer type we can see the generated functions in the assembly code so we'll go to the project properties and go to CC Plus then output files and here we'll select a similar output we'll select assembly with source code let's build the program again so that the files are generated and then let's go to the project directory we'll go to debug folder the other debug folder that is below the project directory the subdirectory and then we'll select source.asm let's open it and let's search for the function Max and you can see that there are two copies of Max function Max for float and Max for integer what would happen if we do not invoke Max function at all so if we just comment this code out and then build again and we'll see the a similar output try to search for the max function and it only shows the max function that is in the comment but there is another Max function so this means that if the function template is not invoked then the function is not generated by the compiler the compiler will generate the function for only those types with which it is invoked the process by which the function is generated is called as instantiation the compiler will examine the arguments of the function template and it will accordingly deduce the type of t once the type of T is deduced the function is instantiated for that particular type so using templates we can create generalized software components these components can be used in different situations and with different kinds of data use of templates leads to high performance algorithms and classes because templates are used by the compiler to generate the code at compile time therefore no runtime costs are involved many libraries have been implemented using templates such as active template Library Windows template Library boost Poco Ace Etc all of these are high performance C plus plus libraries used in various domains as we saw in the earlier example you can use templates to write functions the function template will always begin with the template keyword and in the angular brackets you have to specify the type names a type name is a template type argument and you can specify multiple such type names each type name is a placeholder for the actual type and it can accept any type the type name argument is substituted by the actual type at compilation time the type name can also be used as the return type the compiler uses a process called as argument deduction and through that process it deduces the type of the type name argument by examining the function arguments once it deduces the type the function is instantiated for that particular type note that this process happens during compilation we will understand this process in more detail in the next video see you then [Music] thank you hi and welcome to the next part on templates in this video I'll explain the template argument deduction this is a process by which the template type arguments are deduced the compiler examines each function argument and then from that argument the corresponding type argument is deduced this means if the argument type is integer then the corresponding type argument is deduced as an integer once the type argument is deduced to be of specific type then its subsequent deduction in other function arguments should lead to the same type during template argument deduction no conversions are performed after the deduction process is over successfully the template is instantiated sometimes we may need to override the deduction process of the compiler and we can do that by specifying the types in the template argument list as shown in the example this is required in certain cases and we'll see some examples later a template function or a class will only act as a blueprint this blueprint is used by the compiler to generate the code and the compiler generates the code after the template argument deduction this process is known as template instantiation and this process happens at compilation time the template instantiation happens implicitly in the following cases the first case obviously is when a function template is invoked the second is if you take address of a function template then the compiler is forced to instantiate the function template the third is when you explicitly instantiate a function template and finally if you create an explicit specialization for a function template then in that case also it is instantiated we will learn about explicit instantiation and explicit specialization in the subsequent videos for the template instantiation to work the compiler should be able to see the full definition of the template that is why function and class templates are always defined in a header file templates generally do not use the conventional style of Declaration and definition the definition is implemented in the header file now let's look at some examples of the argument reduction and template instantiation in this example we'll just print the type of T using the type ID operator and we will invoke Max function with different data types this is one and the second would be maybe through a double let's run it in the first case the type name t is deduced to be an end and in the second case it's deduced to be a double now as I mentioned earlier once the type name is deduced then in subsequent function arguments it should be deduced as the same type this means if for some reason the second argument is of a different type let's say it is a float then this is a compiler error because when the compiler examines the arguments from the first argument the t is deduced to be an INT but from the second argument it is deduced to be a float the compiler will not apply any type conversions here that is why this will lead to an error now there are two ways of solving this problem one way is you type cost one of the arguments to the other type so maybe we can type cost 3 to be a float and this would allow the code to compile the second way would be to override the compiler's deduction process by explicitly specifying what should be the type of t so for example if in the second call we specify the first argument as int and the second as double so we want both arguments to be of type double so we can override the compiler's deduction process by specifying the type of arguments okay then now the compiler will not use the argument deduction it will directly replace this t with a double type so these two function calls will cause the compiler to instantiate the max function for float and double time to be instantiated when you take its address so for example if we want to take address of the max function when it is invoked for integers then we can do it like this and this is the pointer to the function Max the argument types are integers and this is how it will look like now we are not invoking the max function for integer types but we got its address that is where the compiler will instantiate the max function for integer types and we can even verify this by first building it and then examining the assembly source you can see that the compiler has instantiated Max for integer types you can also explicitly instantiate a function template so if you want to instantiate Max function for character types we do it like this template Max this will cause the compiler to instantiate the max function for character types note that we are not invoking the max function for care types anywhere else so we will build this and then we'll examine the assembly source and let's search for Max of care there you go the max function for car types has been instantiated by the compiler and finally the instantiation also happens if you create an explicit specialization of the function template but we will look at this feature in the next video see you then [Music] hi and welcome back to the next session on templates in this video I'll explain explicit specialization let's understand it with an example in the previous videos we implemented a function template called Max it accepts two arguments and Returns the maximum value out of those two arguments let's use the max function for comparing strings maybe we have an array of strings and we want to sort those strings so obviously we'll have to compare the strings in order to sort them so we'll create two strings but we'll be using raw strings so I have two pointers A and B and they internally point to the string A and B respectively so we want to find out which string contains the maximum value obviously in string comparison the ASCII values of the characters are compared and let's see if our Max function can do that and will also print the result let's run and it has printed a so obviously that is not right it should have printed B so why do you think it has printed a to understand let's debug the code so we'll run up to this point and if you examine the watch you can see the values inside A and B variables and you can see they both hold addresses and you can also see what those addresses internally contain they contain the values A and B strings and you can see that a has the address which is larger than the address in b and the algorithm that we have implemented in Max function will obviously compare these addresses therefore it will give the wrong result so we need to implement the max algorithm in such a way that when we use it for Strings it should compare the values in the addresses rather than the addresses so how do we do that we can use the feature of explicit specialization in explicit specialization we specialize a function or class template for a particular type we do that because the algorithm that we have implemented may not suit a specific data type or it does not provide correct semantics for some specific data type the other reason why we may want to explicitly specialize a function or class template is because the algorithm that we are implementing we can implement it more optimally for a specific type therefore we can write a new definition for that specific data type using explicit specialization when you specialize a function template or a class template then the definition should be written in a DOT CPP file and not in dot H5 the reason is explicitly specialized functions are already instantiated so if you define them in a header file it will lead to violation of the one definition rule the primary template definition should occur before you specialize function or Clause template now let's go back to the code and create an explicit specialization for the max function so an explicit specialization is written like this we will Define the function Max but it will begin with the keyword template and the template argument list should be empty then we write the return type the return type is going to be constant star then the name of the function and then you can specify the arguments and here we'll write the algorithm that will compare the strings rather than the addresses so we'll use the C function string compare so if x is greater than y then string compare will return a value that is greater than zero so we'll write it like this if x is greater than y then return X otherwise return y and we may also want to print a message here so that we know that the explicit specialized function is getting invoked now if we run this we should see the correct output the first stop debugging then run it now it correctly shows B is greater and you can see it has also printed the message Max const cat Star note that an explicit specialization is already instantiated that is why it should not be defined in a header file it should be defined in a DOT CPP file in explicit specialization you may also specify the type for which you are specializing you can write that type over here now this is optional I would recommend doing this because this way it will be easy to differentiate between explicit specialization and explicit instantiation because both seem to have similar syntax but note that in explicit instantiation there is no template argument list after the keyword template but in explicit specialization after the template keyword you have to specify the empty template argument list so I'm just going to write a comment here that's all for now in the next video we'll look at non-type template arguments see you then [Music] hi and welcome back to the next spot on templates in this video I'll explain non-type template arguments non-type template arguments appear in the template argument list and these are constant Expressions let me show this with an example so we can create a function which will have a non-type template argument such as size and then we can use this size inside the function this function does not accept any arguments we'll just print the value of size to invoke this function we have to specify the value in the template argument list during invocation so we can specify some value here and if we run this we should see the value being printed so you can see three is being printed in the console but whatever values specified here in the template argument list that should be a constant value if we create a variable and try to specify that as an argument that is not going to work if we try to build this this is an error so the error is template parameter size I a variable with non-static storage duration cannot be used as a non-type argument however if we try to use size of the type because this is computed at compile time we can specify this as the argument in the template argument list of the print function so the non-type template arguments should be constant expressions and it should be possible for the compiler to compute them at compile time let's remove this and change it back to 3. the non-type template arguments are always constant expressions this means the variable size that we have here is constant and it cannot be modified let's try to modify it if we build this the compiler will not allow us to build it so size is constant because size is constant we can use it to specify the size of an array like this and if you build this works non-type template arguments are more common with Clauses but with functions they are commonly used with arrays let's create a function that will return the sum of elements of an array and the array can be of any type so we'll create this function called sum and this would accept an array so accept it as a pointer and we'll also have to specify the sites and finally we'll return the sum let's create an array to use the sum function we'll comment out this code forgot the semicolon here let's run it and this is the output to pass an array into a function you have to pass the address of the first element and you also have to pass the size using templates and non-type template arguments you can pass an array into a function without specifying its size explicitly so before I show you that let's create a reference to this array a reference to the array should contain the size of the array so the type is int and in Brackets we'll use the reference operator and here we'll use the size of the array and assign the array to this reference now ref becomes a reference of the array note that we have to specify the size of the array here if we change this to 5 this will not work so there is an error here because the reference is to an array of five elements but the array that we have on the right side only contains four elements so using this concept of reference to an array we can pass this array into a function without specifying the size and we will take advantage of non-track template arguments so I'm going to create a copy of this function let's comment out the old code now this size that I have specified here I'll put it over here as a non-type template argument and the argument to the sum function would be reference to an array earlier I mentioned the non-type template argument is going to be a constant so it should be an expression or a value that is computed at compile time so it can be used to specify the size of the reference to the array and to invoke this function we just need to pass the array variable and it shows a correct output so using reference to an array and non-tech template arguments we can pass an array into a function without explicitly specifying the size this is used by the standard library to implement the global functions STD begin and STD end for arrays so if you want to get the beginning iterator of this array we can use STD begin and if we look into this definition of begin you can see it accepts a non-type template argument and the argument to the begin function is reference to an array a non-type template argument is an expression that is specified in the template argument list this expression is computed at compile time that is why it must be a constant expression the constant expression could be an address a reference integrals null pointer or enums if the constant expression is an address then it should be a static address that means it should have been computed at compile time so you can specify a pointer to a variable or a pointer to a function the non-type template argument is part of the template type the non-type template arguments have been used in the standard library to implement the global begin and end functions which are used to compute the begin and end of static arrays as I mentioned earlier non-type template arguments are more common in classes so we will revisit non-type template arguments again with classes that's all for now I'll see you in the next video [Music] hi and welcome back to the next part on templates in this part I'll explain veritic templates veritik templates are functions and Clauses that can accept arbitrary number of arguments if you have already used C you will know that printf function is a function that can accept any number of arguments it is internally implemented through macros and because of that it has several disadvantages because of macros it is not type safe and secondly such a function cannot accept references as arguments let's try creating such a function without using macros we will use the initializer list feature of C plus 11 to implement this function so we'll create this as a function template so that the function can accept any type of arguments and we can use the range based for Loop to access the individual elements and then we can print those elements now we can invoke this function like this and it works perfectly the problem here is with initializer list the arguments have to be of the same type that means if I want the second argument to be of a floating Point type then the code will not compile because it will fail the template argument deduction this is where Verity templates can step in using variety templates we can write a function that can accept any type and any number of arguments so let's write another version of the print function using validity templates so I'll comment this out so that it doesn't interfere with our implementation so obviously this is going to be a function template and we need to specify the type name now whenever you write a veritech template you need to specify that through the syntax of three dots these three dots are called as ellipses and they are used in various places in C plus plus for example we use Ellipsis to represent an all-cache Block in exception handling now here ellipses signifies a very rich template and we need to specify the name that will represent the variable number of type names so we'll give a name here called as perms this is known as the template parameter pack s does not represent type name rather it is an alias to the list of type names you can imagine params to be a pack of template type names the next thing is to define the print function with the arguments now we will use params to signify the arguments of the function this is known as the function parameter pack and it will be automatically expanded by the compiler let's write that here now this function can accept any number and any type of arguments so let's invoke it with different type of arguments the arguments that are being specified here will be automatically expanded by the compiler over here now the question is how do we access the individual arguments the thing is you cannot access the individual arguments directly instead you will have to rely on recursion so we use recursion to access the individual arguments that means in each recursive call the number of arguments is reduced by one and just like in normal recursion where we have a condition that ends the recursion here also we need something that will end the recursion and that has to be done by writing another print function without using the variatic template and that function is called as the base case function and we will learn how to write that base case so let's invoke this print function recursively to pass the function parameter pack you have to use the syntax like this now the compiler will invoke the print function with the same arguments that were passed in the print function from Main but if we compile this code it will compile fine but the compiler gives a warning obviously the code that we have written will cause a runtime stack Overflow because of infinite recursion as I mentioned earlier we need to write a base case that will stop the recursion and we have to do that by passing one more argument to print function so we will specify one more type name and this will be the first argument now when we compile this it gives an error it says no matching overloaded function found expects two arguments zero provided so the thing is in each recursive call the number of arguments is reduced by one and finally print will be invoked with zero number of arguments let me explain that how that works so in the first case print is invoked with these arguments and the call will go into the print function and then the print function will be recursively invoked now obviously one will be passed as an argument here and 2.53 and 4 will be passed as arguments here they will be part of the function parameter packed then we pass the function parameter pack to print function again obviously the arguments that we passed to the print function again would be 2.53 and 4. so the call will be 2.5 3 and 4. you can see that the number of parameters to print function has reduced by 1. now obviously when print is again invoked with these number of arguments 2.5 will become the first argument that will be captured in a variable and 3 and 4 will be passed as arguments here so they will become part of this function parameter pack so obviously the next time when print is invoked it will be invoked like this 3 comma 4. now when in this case print is invoked 3 will become part of the first argument a and the function parameter pack will only contain four that means when print is invoked again it will be invoked as 4. so you see in each recursive call the number of arguments is reduced by one obviously when print of 4 is invoked 4 will become the first parameter and it will be captured in a and the function parameter pack will be empty that means when print is invoked it will be invoked with zero number of arguments so the next call will be print and it will not accept any arguments so during template instantiation the compiler will look for a function print that does not accept any arguments and obviously we don't have such a function but we can write a function called print that does not accept any arguments at all and that function is going to be our base case function that will stop the recursion so let's go ahead and write this print function and now if we build this it does not give any error now we can access individual arguments and perform operations on them we will understand this process Again by looking at the call stack so I'll keep a breakpoint in print function and we'll start the debugging so it has reached the base case we'll open the call stack here print is invoked with four arguments so you can see the type names are int double int and car con star and the next call is going to be the recursive call where the first argument is removed because that is consumed so the first type name is double then int then care con star then in the next recursive call it's going to be int and Care con star and then subsequent call will only have care con store that is the last parameter that is 4 and finally after that is consumed as the first argument here it will invoke print without any arguments and finally the recursion will stop we'll stop here and we will continue this in the next video see you then [Music] hi welcome back we will continue our discussion on Verity templates in the last video I explained how we use recursion with Verity templates and how to stop that recursion using the base case function and we also saw how during recursion the number of arguments is reduced by 1. now we will print all the arguments that are passed into the Sprint function and in the base case we will print end offline build this and run and you can see it's printing the arguments that we pass to print function but obviously they are printed together so we would want to have some kind of separator when they are printed so we'll do one thing we'll just print a comma here so that will be our separator but we can see an extra comma that is being printed after the last argument is printed so how do we take care of that we could print a comma only when we know the function parameter pack is not empty so some way we need to find out what is the number of arguments in the function parameter pack and we can do that through the periodic size of operator so we can use size of to find out what is the number of parameters in the function parameter pack and we can also use this size of operator to find out how many template parameters are in the template parameter pack and we'll comment this out let's run and you can see in the first call the number of parameters was 3 in the second it was 2 then 1 and final is 0. so we can take advantage of size off to check the number of parameters in the function parameter pack and accordingly decide whether to print a comma or not so if size of args is not equal to 0 then we will print a comma and obviously when the function parameter pack is empty the comma will not be printed that would mean the last argument is being printed perfect if we pass user defined types to print function then obviously multiple copies will be created because we're passing by value so let's pass the arguments by constant reference and here we'll specify that the parameters are reference types like this let's try this out with our integer Clause so I'm going to add the integer class to the project okay I've added it to the project let's include the appropriate header file now we will invoke print function with our integer types and we'll comment out the first call so everything is fine it works the problem here is that even though we are passing an R value here as an argument to print function when it is passed again during recursive call to print it will be passed as an L value and not as an R value so we would like to use perfect forwarding here and obviously for that we'll specify the arguments as r value references remember the reference collapsing rules when we pass an L value to this function then this argument will become L value reference but if we pass an R value to this function as an argument then this will become an R value reference and we would like the same thing to happen to this function parameter pack so this would be r value reference and we'll use STD forward here note the syntax the ellipses comes outside the brackets of STD forward now depending on whether L values or R values are passed to this function they will be appropriately forwarded to the next recursive call that's it for now in the next video we'll start with class templates see you there [Music] hi welcome back in this video we'll start with class templates class templates are frequently used in C plus plus to create classes that should be able to handle different types therefore it is more common to use class templates with containers C plus plus standard Library already contains implementations of several containers that are implemented through templates such as Vector list set map Etc to understand class templates we will create a clause called as stack initially we will assume that it can only hold integers and we'll create a stack of 512 integers we'll initialize the top to -1 then we'll add functions such as push pop top is empty and in pop we'll simply reduce the top value by 1. and if you want to access the element at the top of the stack we can use the top function we'll also write a function called is empty and it would be empty if top is equal to equal to -1 let's create an instance of this stack all right and then in a while loop we can print all the elements that have been pushed into the stack while the stack is not empty get the value from the top of the stack and then pop it off so it shows the correct output but this stack can be used only for storing integers what if we want to create a stack of Floats or doubles or strings obviously we would not want to create a stack class for each type instead we can use class templates so let's convert this class into a class template the class declaration will begin with template keyword and the type name as usual and the array will be of type T and this would change to T because it could also be a user defined type which should pass by constant reference and top would be cons T ampersand now when we have to create an instance of this stack we have to specify the type in the template argument list so if you want to create a stack of integers you'll specify the type end here to create a stack of floats you can specify the type here so you see how easy it is to use the same stack clause for different types obviously the compatible instantiate the stack class for all the types that it is instantiated for note that only those member functions are instantiated that are invoked if we do not invoke some of the member functions then they are not instantiated class templates can also accept non-type template arguments so we can specify the size of the stack from here and this size is constant and we can use it as size of this array and when we create the instance of the stack we can specify the size here itself so this will become a stack of 10 floats this is much better than using a constant value in M underscore buffer because with this non-type template argument we can decide what should be the type of the stack at compile time but we do that without hard coding the value inside the class so far we have defined all the member functions in the class itself if you define the member functions outside the class then you have to follow the syntax of the templates so for example if I Define the pop function outside the class then the definition should be preceded with the Declaration of the template type name t and int size and the return type would be wide and then the name of the class now the name of the class is not only stack the template parameters are part of the type of the class that is why the type of the class is not stack it is stack of T comma size and then the name of the function and then its implementation so remember in templates the template parameters are part of the type but there is one more thing let's create a factory method for this stack class a factory method is a method that creates instance of the class so we'll create a function which is a static function that will return instance of the stack class we'll call this create and this would create an instance of the stack so here we need to specify the type that is T and the size this would create a temporary object stack which we are then returning by value and we can use it like this the object that create returns is an object of a class of type stack float comma 10. if the size here is different then these are not the same types because as I mentioned earlier the template parameters are part of the type of the class or the function so the instance returned by create is different from this type let's change it back to 10 . now we would also implement the create function definition outside the class so the implementation would be as usual we'll have to precede the definition with the type of the template the return type is stack then stack of type T size and then create then we can copy this code and put it here now this code will not compile the reason is the compiler doesn't know what this type is earlier when we had defined the function create inside the class since the name was occurring inside the class it did not need the complete template parameters this is known as the shorthand notation in shorthand notation you do not need to specify the template parameters and you can write shorthand notation only if that type occurs inside the class definition you cannot write shorthand definition outside the class so you'll have to use the complete type of the stack class here if we try to build this the compiler complains says use of class template requires template argument list and that is for this name so that's why the shorthand notation Works only inside the class not outside it so here we have to specify all the template parameters and this compiles fine we would also Implement a copy Constructor for this class and we would like to perform the copy of the attributes manually so here we can use the shorthand notation for the stack class we'll also have to provide a default Constructor we'll let the compiler generate one for us and we'll also like to initialize stop before the for Loop and since top starts from -1 we will use less than equal to top here and then we'll create a copy of the stack and instead of s we'll use S2 here run it and it works fine so you must have noticed that the argument to the copy Constructor uses the shorthand notation the reason is it appears within the class you can also use the long hand notation but that is not required if you define this copy Constructor function outside the class then would you need the shorthand notation or the long hand notation for the stack type you can try it out for yourself and you can let me know in the comments that's all for now in the next video we'll look at some more features of class templates see you later [Music] thank you hi welcome to the next part on templates in this part I'll explain explicit specialization of class templates I have written a class called as pretty printer that can be used to pretty print some data to use this class we'll have to create its instance and store the data in it that we want to pretty print so the data type will be a template type and we will initialize this data through the Constructor and then in print will simply print the data since we are pretty printing let's add some decoration to the data that is printed maybe we can use braces all right and we'll also create one more function called as get data that Returns the pointer to the data and we can use this for different types so let's create instance of pre-printer for integer type and we'll pass the address of the data then we'll call Print and we can also create a pretty printer for float and then print let's run it and see the output and this is how it looks like perfect let's use pretty printer for more types assume we've also want to print a string so we want to pre-print the string through the pretty printer class so we create instance of 3D printer and we specify the type as cadstar and pass B here and then we'll call print we'll comment out the earlier code let's build this and it gives an error so the error is cannot convert argument one from care star to cast star star the problem here is when we use cash store as a template parameter then the type of T is T star the Declaration here becomes a pointer to pointer that is T star star and this also becomes T star star so the argument that we have to pass to the Constructor would be pointed to a pointer but we are only passing a car star which is just a pointer so this would not compile so that is why we may have to pass this as a pointer to pointer and then let's build it it builds fine let's run it and it prints the correct data let's also try to use the function get data so we want the data back from the pre-printer class and when we build this it gives a compile time error the reason being because we use the template parameters cast star the type of T is T star and the get data now returns T star star so you see all this becomes counterintuitive when we use pretty printer with cache start type on the other hand what we could have done is we could have just specified the type as care and we'd just pass the pointer here so obviously the type of T would be only T star and if we build this this works we can get the data back from the Pretty printer class without any change in the syntax let's run this unfortunately it only prints the first character and not the entire string the reason for printing only the first character is because M underscore P data is a pointer to a string and when we apply asterisk on it we dereference it so it would only print the first character so you see using the pretty printer with a string type does not give correct results but the pretty printer Clause works for other types in this case we can explicitly specialize pretty printer for the string types so let's go ahead and create a specialization for the string types so we'll create a copy of this and as we learned in the explicit specialization of function templates when you create a specialization the template argument list has to be empty and you need to specify the type here so this becomes explicit specialization of the pretty printer class for the Cash Store type and now this is going to be care star this would also be care star and we will remove the asterisk from here and this would be replaced by cap and we'll also have to change this to Cache star let's run now it correctly prints the string so the explicit specialization now works for the string types that is cache start types that's all for now in the next video we'll see some more examples of explicit specialization see you then [Music] hi we will continue our discussion on explicit specialization of class templates let's try pretty printer with a vector we'll create a vector of integers and we want to pretty print the data inside the vector so we'll create a pretty printer for Vector type of integers and then let's print we build and it doesn't work because M underscore P data is appointed to the vector and when we apply asterisk on it it will return the vector object itself and the insertion operator is not overloaded for that class so obviously we can also explicitly specialize this class for the vector type and we can do that very easily by creating the specialization like this this is going to be a vector of type int and this would also be a vector of type integers and instead of printing the vector like this we will use arranged based for Loop and this is how the print function will look like and this also needs to be changed to Vector of type it let's build this again and run it and now you can see it correctly prints the data that is inside the vector if you compare the explicit specialization of the pretty printer clause for vector and Cash Store you will notice that for cashstar we had to specialize the entire class because even get data was not working when we used 3D printer for a cash store because the type of T was becoming T star star and the return type was getting resolved to T star star however for Vector that is not a problem the problem was only with printing so instead of specializing the entire class for Vector we could have just specialized the member function print so we will write a specialized version of the print function for the vector type and to do that we just have to write the definition of that function outside the class not inside the class obviously the definition would start with template with empty template argument list the return type is wide then the name of the class and here we specify the type for which we are specializing this function and we can copy the code that we wrote earlier over here and we don't need this specialization for the vector and let's build this run it and it works for the vector type note that when you explicitly specialize a member function template then its definition should be in the namespace scope that means you cannot write the definition of this explicit specialization inside the class it has to be outside the class that's all for now in the next video I'll explain partial specialization see you then [Music] thank you hi and welcome back to the next spot of templates in this video we'll learn about partial specialization of class templates in partial specialization we specialize some of the template parameters in a class so the difference between explicit specialization and partial specialization is that in explicit specialization all the template parameters are specialized but in partial specialization only some of the template parameters are specialized so we will go back to our old example where we created the class pretty printer we would add one more template parameter and this would be a non-type template parameter and we'll call this columns Imagine The Columns contains a value that is used by the print function to find out what is the available width to print the data so we can print the value of the columns here and obviously this value is going to be constant we cannot modify it and then we can create the instance of pretty printer for any type and we'll also need to create some kind of data and then we invoke print let's run it and you can see it shows the columns available are 40. assume that this class is used on devices where the number of columns are 80. and this is the most common number of columns available on these devices so we would like to take advantage of this number and print the data in the print function in a more efficient way or we can format it in a better way in that case we would like to find out when the value of columns is 80 and then accordingly we can decide to print the data in a different way obviously we can do it at runtime we can have conditional statements in print function and then we can check for the value of columns but there is a more efficient way we can partially specialize the pretty printer class for the value of columns so in partial specialization we will specialize some of the values of the template parameters since we are specializing the second non-type parameter the first parameter will be type name and when we create the class pretty printer we will have to specify the type name that is the first template argument and then the value of the second argument which is going to be 80. and then based on this we will decide how to implement the functions of the class so we can create a copy and we will change this message this variable will not be available and let's change this to 80 and when we run this you can see the compiler has chosen the partial specialization let's create one more class in our operator overloading lectures we discussed a concept of raii which is used for creating smart pointers and we had implemented a very basic smart pointer for integer pointers now with the knowledge of templates we can create a smart pointer that can work with any type let's call this smart pointer will contain a Constructor through which we initialize this member and then remember we had overloaded the arrow operator and we also overloaded the asterisk operator to return the value at address and finally the destructor which will free the memory of the internal pointer and then we can use this smart pointer and it will automatically free the memory at the end of the scope and we can print the value using the asterisk operator let's run it and you see the value 3. what if we want to use Smart pointer with a dynamic array so instead of this being a simple integer pointer will make this as an integer array so smart pointer now holds a pointer to an array and the class will not give correct semantics and behavior for this smart pointer when it internally points to an integer array first of all we cannot access the elements of the array using this smart pointer secondly the implementation of the destructor for an array is not correct it should use the delete for arrays so in this case we can partially specialize the smart pointer class for array types and we can do it like this we'll create a copy of the smart pointer and here we will specialize this class for array types so this indicates whenever the smart pointer class is instantiated with any type but if it is an array then this specialization will be used and obviously the arrow and asterisk operators do not make sense for an array so we will remove these and instead replace with the overloaded subscript operator and in the destructor we'll use the correct form of delete to free the memory and when we create the instance of smart pointer that is going to hold an array then we specify the argument as an array so this will indicate that the smart pointer is being instantiated for an array type and obviously the compiler will choose the partial specialization you can see Star S1 does not work here instead we can use the subscript operator and the same operator can be used for reading and writing and this should be index and when we run this it works and you can see the correct value being printed through the C out statement the smart pointers in the standard Library also provide partial specialization for the array types that's all for now in the next video we'll look at some more C plus 11 features of templates see you later [Music] hi and welcome back to the next part on templates in this video I'll explain type aliases but before that I would like to revisit type definitions type definitions can be created through the keyword type Def and using this keyword we can introduce a new name for an existing type the new name then becomes a synonym of that type this way it is useful to construct a shorter or more meaningful names for existing type def also helps us to simplify Declaration of some types especially with function pointers and templates using type definitions it is possible to hide the implementation details of the types this way we could change the type of the type definition without affecting the client code C plus standard Library itself provides type definitions for many standard classes such as stream classes string class Etc for example when we use the string type in our code we're actually using a type definition of a class called basic string so the type definitions reduce the complexity of using the type remember that when creating a type definition it does not introduce a new type it only introduces a new name for existing type these are some examples of type definitions type definitions are commonly used for representing unsigned integers so instead of writing unsigned int we just have to write the type diff uint the same goes for long long time while creating long long types the Declaration seems too long pun intended so we can reduce it to a type diff called as a long type definitions also help us reduce the complexity of using templates in this example I have created a vector of list of employees and the type definition is called as teens instead of using the complete declaration which includes the vector list and the employee type we can use the type diff when creating the instance of iterator to iterate even then we can use the type diff so you see the complexity of the code is reduced but obviously in C plus 11 we would have preferred to use Auto here type definitions also can be used to create type definitions for function pointers this is especially useful when function pointers appear as arguments into functions or when they are used as return types e plus plus 11 introduced a new feature called as type alias type Alias also creates a name that is a synonym of an existing type as with type definitions it does not introduce a new type and it is exactly similar to that of a type diff declaration to create a type Alias we use the using keyword the using keyword requires an identifier and you can specify the type on the right hand side then the identifier will act as a synonym for that type these are some of the examples of usage of type Alias note that using the type Alias seems more natural because this is consistent to the way we initialize variables so in the first example uint is an alias of unsigned end the second example is L log that is an alias of long long type in the third example the teams is an alias of a vector of list of employees and finally the last example shows how we can create an alias for a function pointer type the error FN type is a type that represents a function pointer that accepts an integer and returns a const gas star let's try out these examples in Visual Studio I have already written some code so there is a function called get error message that accepts an error number and Returns the string associated with that error number so for the time being we're just returning the string called empty and show error is a function that accepts a function pointer that accepts an integer and returns a const care star so obviously we can pass the address of get error message in this show edit function but look at the Declaration of show error function it looks quite complex due to usage of function pointer we can reduce the complexity using the type definition or a type Alias if we use a type definition then we can create it like this now pfn is a type that represents a function pointer so instead of writing the entire declaration here we can just write the type name and a variable and we can do the same thing here and then we can invoke show error by passing the address of the function we forgot asterisk here using type aliases we could have created the function pointer type like this using pfn equal to con star then the brackets we have to write asterisk that represents a function pointer type now this pfn is an alias of this function pointer type if you compare the two ways through which the Alias is created the second seems more natural so we'll comment out the type diff declaration now if we use type definitions with templates like this let's say this is list of names obviously this is quite a long declaration so we might want to create a type definition for this so that we can use this type in many places in our program without having to resort to writing this long declaration so we can create a typedef and this could be replaced with names the disadvantage of using type defit templates is that type definitions cannot be templatized that means if I want to use names in some other context let's say I want to create a vector of list of players then I cannot templatize this with a template parameter such as player but using type aliases we can create an alias template so if we want to use this type in different contexts but we should be able to templatize the type here then we can use Alias templates and we do it like this template type name t and using names equal to and then here we'll specify the type name t now when you use names you can use it in context of names for any entity so it could be a string or you could also use it with some other type let's say you want to have names of names you can even do that and this could be string you may also permanently bind a type in this list so if you want to bind it with strings then you can do it like this and obviously you cannot templatize this with any other type and we'll remove this line so you can see that Alias templates have a clear advantage over type definitions this is the end of the section for templates in the next section I'll start with Lambda Expressions see you there