Search

13.7 — Partial template specialization

In lesson 13.4 -- Template expression parameters, you learned how expression parameters could be used to parameterize template classes.

Let’s take another look at the Static Array class we used in one of our previous examples:

This class takes two template parameters, a type parameter, and an expression parameter.

Now, let’s say we wanted to write a function to print out the whole array. Although we could implement this as a member function, we’re going to do it as a non-member function instead because it will make the successive examples easier to follow.

Using templates, we might write something like this:

This would allow us to do the following:

and get the following result:

0 1 2 3

Although this works, it has a design flaw. Consider the following:

(We covered strcpy_s in lesson 6.6 -- C-style strings if you need a refresher)

This program will compile, execute, and produce the following value (or one similar):

H e l l o ,   W o r l d !

For non-char types, it makes sense to put a space between each array element, so they don’t run together. However, with a char type, it makes more sense to print everything run together as a C-style string, which our print() function doesn’t do.

So how can we fix this?

Template specialization to the rescue?

One might first think of using template specialization. The problem with full template specialization is that all template parameters must be explicitly defined.

Consider:

As you can see, we’ve now provided an overloaded print function for fully specialized StaticArray<char, 14>. Indeed, this prints:

Hello, world!

Although this solves the issue of making sure print() can be called with an StaticArray, it brings up another problem: using full template specialization means we have to explicitly define the length of the array this function will accept! Consider the following example:

Calling print() with char12 will call the version of print() that takes a StaticArray<T, size>, because char12 is of type StaticArray<char, 12>, and our overloaded print() will only be called when passed a StaticArray<char, 14>.

Although we could make a copy of print() that handles StaticArray<char, 12>, what happens when we want to call print() will an array size of 5, or 22? We’d have to copy the function for each different array size. That’s redundant.

Obviously full template specialization is too restrictive a solution here. The solution we are looking for is partial template specialization.

Partial template specialization

Partial template specialization allows us to specialize classes (but not functions!) where some, but not all, of the template parameters have been explicitly defined. For our challenge above, the ideal solution would be to have our overloaded print function work with StaticArray of type char, but leave the length expression parameter templated so it can vary as needed. Partial template specialization allows us to do just that!

Here’s our example with an overloaded print function that takes a partially specialized StaticArray:

As you can see here, we’ve explicitly declared that this function will only work for StaticArray of type char, but size is still a templated expression parameter, so it will work for char arrays of any size. That’s all there is to it!

Here’s a full program using this:

This prints:

Hello, world! Hello, mom!

Just as we expect.

Note that as of C++14, partial template specialization can only be used with classes, not template functions (functions must be fully specialized).

13.8 -- Partial template specialization for pointers
Index
13.6 -- Class template specialization

12 comments to 13.7 — Partial template specialization

  • george

    Is this

    an implicit initialization for the value pointed by m_tValue? In other words, is it equivalent to:

    • LW

      good question, I have the same thought… anyone can confirm this usage?

    • Steve

      Good question. This is implicit assignment like:

      which means you are correct.

  • Lokesh

    The second last example(code below) doesn’t work for char* because the constructor

    allocates memory for a single character only. Although sometimes the programmer may want that but most times when dealing with char* type we mostly refer to strings as there is no point in using a pointer to point to a single character. Thus only the first character in the string(which is passed by the user) will be copied. We still have to do full template specialization for char*
    I think you should mention that in the lesson.

    • Lokesh

      I thought I should provide the code for it because there are a few subtle differences which are very important.

      Also note that we cannot use explicit specialization for Storage<T*>::Print() function when T is char* because it will print garbage since size of string is not known.

      • Alex

        I’m not sure I see offhand why Print() wouldn’t print properly. m_tValue should be a copy of the original null-terminated tValue string. Therefore, it should print until it encounters the null terminator, which should appear at the end of the string.

        • Lokesh

          Yes, you are right. I forgot to mention that this problem occurs only with the templated Storage class(not the specialized version for char*) as it is given in the example code where we allocate a single character in the constructor.

    • Alex

      Fair point. I’ve added a note into the lesson.

  • Ola Sh

    Hello Alex,

    Thanks again for your nice tutorials. While practicing with your examples, I noticed that Visual Studio C++ compiler could not print out the address of a character(char) variable or array. Does this have anything to do with how C++ stores char variables? Also , does C++ allow partial template specialization of class member functions. Please see my code below. I tried specializing the Storage class for char* using partial template specialization, but the code failed to compile. The compiler gave many errors when it reached the specialized constructor for char*. Thanks for your help.

    • Alex

      Visual Studio should be able to print the address of a char or array. For a char, you’ll have to use the address-of operator (&). For an array, you can just print the array variable since it’s already a pointer (or will decay into one).

      C++ does not support partial specialization of single member functions. You have to partially specialize the entire class.

  • Ritter G

    so in the public portion of this code is that a function pointer for getbuffer?

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter