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