WEBVTT

00:00.120 --> 00:00.690
Hello again!

00:01.170 --> 00:08.880
In this video we are going to look at template specialization. Templates are generic, so we get the same

00:08.880 --> 00:16.020
behaviour when we instantiate our class template or function template, regardless of which types we

00:16.020 --> 00:18.090
use to instantiate it with.

00:19.750 --> 00:21.490
And usually that is what we want.

00:22.150 --> 00:28.540
Sometimes, though, we may want to get different behaviour for certain types. For example, we

00:28.540 --> 00:31.960
may want to be able to handle some types differently.

00:33.130 --> 00:41.770
The Vector Class in the C++ library is a class template. It has an array whose elements are the type

00:41.770 --> 00:50.410
of the template parameter. Unless it is a vector of bool, in which case it is implemented as a bitmap. Because

00:50.410 --> 00:54.580
someone, a long time ago, thought that would be an interesting way to do things.

00:57.450 --> 01:01.920
Another possibility is that the code does not behave correctly for some types.

01:02.610 --> 01:09.960
If we have a plus operator and the arguments are both library strings, then that will behave correctly.

01:10.230 --> 01:16.260
If they are both C strings, then that will not work properly. And we need to do something else if

01:16.260 --> 01:17.640
we have C-style strings.

01:18.990 --> 01:22.860
And also, we may want to be able to optimize the code for certain types.

01:23.640 --> 01:30.000
If you remember the list class, then calling generic algorithms for the list is very inefficient.

01:30.420 --> 01:33.150
It is much faster to call the member functions instead.

01:33.840 --> 01:39.410
So you want to have some code which calls the list member functions, instead of the standard library

01:39.420 --> 01:40.710
generic algorithms.

01:42.300 --> 01:45.630
And we can do all that, by using a template specialization.

01:48.160 --> 01:50.980
So here is how the vector class could be implemented.

01:51.640 --> 01:59.560
We have a generic vector class. Template, angle bracket, type name or class "T". That is the template parameter.

01:59.860 --> 02:06.190
And then the class will implement a vector, using an array, whose elements are this parameter type "T".

02:09.250 --> 02:11.950
For the bool type, we have a specialization.

02:12.550 --> 02:14.260
The syntax is a bit different.

02:15.010 --> 02:21.880
We leave these angle brackets empty, and instead we put the parameter after the name of the class.

02:22.720 --> 02:30.010
So this is a vector whose elements are bool. And then in the body, we would implement that using a bitmap.

02:31.930 --> 02:37.630
You will notice that I have written the specialization immediately after the generic definition, and there

02:37.630 --> 02:38.470
is a reason for that.

02:42.340 --> 02:44.110
And that is how you should normally write things.

02:44.680 --> 02:50.680
If you put the specialization before the generic template, then it will not compile. Because the compiler

02:51.070 --> 02:53.140
needs to know about the generic template.

02:53.650 --> 02:58.630
If the generic template is not visible, then the specialization will not compile, again.

02:59.950 --> 03:06.130
If you are instantiating the template, and the specialization is not visible, and the generic template is

03:06.130 --> 03:09.730
visible, then the compiler will use the generic template.

03:10.480 --> 03:15.970
So the simplest way to make things work is to write the specialization immediately after the generic

03:15.970 --> 03:16.410
version.

03:19.360 --> 03:21.370
How does the compiler know which version to use?

03:21.970 --> 03:28.240
When the compiler instantiates a template, it will look at all the alternatives which match, and then

03:28.240 --> 03:30.670
it will choose the one which is the most specific.

03:31.030 --> 03:37.360
If we have this, then the compiler has a choice between the specialization for bool and the generic

03:37.360 --> 03:44.050
version where the parameter is equal to bool. And the specialization is more specific than the generic

03:44.050 --> 03:44.470
version.

03:45.040 --> 03:48.610
So the compiler will instantiate the bool specialization.

03:51.460 --> 03:52.600
Let's try that out.

03:52.630 --> 03:56.740
So here is a Vector class, with capital 'v', to avoid any confusion.

03:59.260 --> 04:04.390
There is the specialization with the empty angle brackets and the parameter

04:04.420 --> 04:05.830
after the name of the class.

04:06.700 --> 04:11.980
These both have identify() member functions, so we know which version has been instantiated.

04:13.060 --> 04:17.950
And then, in the main function, we instantiate a Vector of ints and a Vector of bool.

04:18.880 --> 04:23.440
The Vector of int will be instantiated using the generic template, because that is the only one which

04:23.440 --> 04:30.820
matches. The Vector of bool will be instantiated using the bool specialization, because that is a better match

04:30.820 --> 04:31.960
than the generic version.

04:33.010 --> 04:36.190
So let's see what we get when we call the identify() functions.

04:38.420 --> 04:45.380
So as we expected, the Vector of has been instantiated using the generic Vector, and the Vector of bool

04:45.380 --> 04:48.410
has been instantiated using the specialization.

04:55.860 --> 04:57.690
Let's try this now with functions.

04:58.260 --> 05:04.770
We have a generic function which takes a container, and calls the standard library

05:04.830 --> 05:05.850
reverse() algorithm.

05:09.200 --> 05:14.600
This will work very well with the containers in the library, except for the standard list.

05:15.530 --> 05:20.210
For the list, we want to call the member function, because that will be much more efficient.

05:20.870 --> 05:24.320
So we write a specialization, for the list.

05:25.220 --> 05:29.750
Now we want this to work for any type of list, not just a list of ints or a list of strings.

05:30.650 --> 05:33.140
And the type of the list depends on the type of the element.

05:33.800 --> 05:40.280
So we need to write a template function which takes the type of the element as the parameter.

05:41.150 --> 05:46.010
And then we can have a list of this generic element type as the argument.

05:46.640 --> 05:51.260
So this will call the reverse() for any list, a list which has any type as arguments.

05:53.360 --> 05:58.820
And then we create a vector. We call the reverse() function, which should call the generic version.

05:59.990 --> 06:04.730
And then we call it again with a list, which should call the specialization for the list.

06:06.880 --> 06:07.270
Okay.

06:12.080 --> 06:16.200
So this works very well if we have a single type that we want to use for the parameter.

06:17.150 --> 06:20.780
If we have different types, then we have to write a different specialization for each type.

06:21.440 --> 06:25.310
But if those types are related in some way, then there is a shortcut.

06:25.310 --> 06:27.770
We can use a partial specialization.

06:28.610 --> 06:34.190
For example, if you want to have a specialization for parameters which are pointers, then we can do

06:34.190 --> 06:34.490
that.

06:35.270 --> 06:39.470
This is only allowed for class and value templates, not for function templates.

06:40.250 --> 06:43.760
And there are some limitations on the arguments, which I will not go into.

06:46.200 --> 06:53.280
So with our Vector class, again, we have the generic Vector. And then we have a partial specialization,

06:53.640 --> 06:55.800
for Vectors whose elements are pointers.

06:56.730 --> 07:03.510
So we still have the "typename T" or the "class T" in angle brackets here, but we also have the specialized

07:03.570 --> 07:05.220
type after the class name.

07:05.880 --> 07:09.000
So this is halfway between the generic and the specialized version.

07:10.410 --> 07:12.240
Then if we have a Vector whose

07:13.900 --> 07:20.620
elements are pointers, then this partial specialization will be instantiated. And for non-pointers, the

07:20.620 --> 07:23.950
generic template will be instantiated.

07:27.060 --> 07:33.890
So we have the same Vector class again, the same generic template. And now we have a partial specialization

07:33.900 --> 07:34.740
for pointers.

07:36.920 --> 07:44.120
So we still have the type parameter, but this can take any kind of pointer. And then, this will be instantiated

07:44.120 --> 07:45.920
with a pointer to the type parameter.

07:48.610 --> 07:54.160
And then we create a Vector of int and a Vector of pointers to int, and we call the identify() functions.

07:56.550 --> 08:02.010
So the Vector of int will be instantiated using the the generic version, because that is the best match.

08:02.910 --> 08:07.050
The Vector of pointers will be instantiated using the partial specialization.

08:07.830 --> 08:09.270
Okay, so that is it for this video.

08:09.810 --> 08:10.680
I will see you next time.

08:10.920 --> 08:13.080
Until then, keep coding!
