×

Get in touch with Binary

Binary Studio website uses cookies to enhance your browsing experience. By continuing to use our site, you agree to our Privacy Policy and use of cookies.

Learn more more arrow
Agree
andrew.kramarenko@binary-studio.com'
Andrew Kramarenko C++ Developer 26.08.2014

8. Template as double-edged sword: diving with ducks


Introduction

In previous articles I have already described a lot of things about templates (the full list of articles you can find at the end). I told basic information about templates: their disadvantages, interacting with OOP, typename keyword, but it is not enough! There are still many things to investigate and learn.

Today my topics are specification of templates and duck typing technique which forms basis for templates.

Template specification

As you already know that template class\function provides generating of code for given types. However, what should you do if you need to change behavior of template code for some reasons for specific type? This is for what template specification stands for. It provides instrument to completely change implementation of template for some type or set of types.

Let's begin with the following example of template class:

I have declared template class which keeps some data and it must be a container with continuous item - for this I will use static arrays. In constructor of this class you see that input argument will be copied to private field someData. Method ExtendWithValue() allocates new dynamic array in which copies internal data, adds input value to the end of dynamic array and returns it. Yep, it means that there will be returned new array which is bigger than internal array on one item and its last item will be passed value. It is some kind of extending. Let's see it in action:

So, in line (1.1) there is declared static array with dimension - 3 and items - 1, 2, 3. In line (1.2) there is an instance of our template class which template arguments are: TDataKeeper is int[3] and TDataType is int. This instance holds copy of passed array as argument. Finally in line (1.3) method ExtendWithValue(4) is called which returns new array whith dimension - 4 and its items - 1, 2, 3, 4. Those items are printed to standard output.

Okay, after some time we want something similar but with std::string as template argument. Most probably it won't work, but template specification is going to help us! See the following code with specification:

Code above declares specification of template class SpecificationTemplate for types std::string and char. Let's observe lines in their order. Line (2.1) contains line with template keyword, but it has empty template argument list! Because in next line (2.2) we manually specify template arguments as TDataKeeper is std::string and TDataType is char. So, in lines (2.3) and (2.4) we can use those types directly which lets us to implement SpecificationTemplate class in a different way then the main template. For example in line (2.5) we use method std::string::push_back() to extend copy of internal string.

Thus it works in the following example:

Without specification of template for std::string this code will cause compile errors, but we have declared specification for such types and compiler can use it here. As you see specification has absolutely different implementation, because instead of auto-generating new code compiler takes our specified SpecificationTemplate<std::string, char>.

Of course, specification of templates doesn't need concretization of all template arguments. Header of SpecificationTemplate can look like this:

Actually, I have already mentioned this technique when i was talking about std::unique_ptr<T> for single instances and std::unique_ptr<T[]> for dynamic arrays. Now it must be obvious for you that correct freeing of allocated memory by new and new[] is provided by specifying template with correct destructor.

Duck typing

or can you quack for me?

Duck test says:

When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.

So how it looks in programming? Especially in C++?

As always I will start  with some examples to show:

1. I want to begin from afar with very common practice of command pattern implementation, I think you know it:

As you see I have used interface of abstract class Command to implement two different commands AwesomeCommand0 and AwesomeComman1 for using them through one function which executes them having no idea what command it is  exactly, but it knows about their parent class.

2. Now let's make the same, but without inheritance with help of templates. Check it out in the following code:

As you see AdorableCommand0 and AdorableCommand1 don't have same parent, BUT at the same time they use in template function ExecuteTCommand(). Furthermore ExecuteTCommand can handle instances of classes AwesomeCommand0 and AwesomeCommand1 at the same time. It is because of duck typing.

Templates have such mechanism for generating code: if template argument type has every property which is used in code than it is duck... I am sorry: correct code and can be generated anyway, otherwise it will cause compile errors during building. Because duck typing in C++ has static behavior during compiling process.

If you tried to use templates from some library, probably you would face with such compile errors because your implementation wasn't duck and it would go away when you make it quacking.

In such way by help of duck typing templates provide style of typing in which instance can have valid semantic without inheritance or explicit interface. On the other hand it causes overhead with looking what is necessary for type to use it in template code. Programmer have to look up for it.

Conclusion

in this article I continued talking about templates. I have dived deeper with you in a template specification with duck typing.

First one provides powerful method to change implementation of original template even for other purpose with specified type or types, but you have to remember that someone else can have no idea about big changes in behavior of template with specified types.

Moreover, I have shown duck typing in C++ which is presented by static checking of type properties in template code. Can given type be used or not? It can be used for providing common usage of instances of different type without its inheritance from parent class or having explicit interface. On the other hand it can cause more overhead than normal.

In the next article I will talk about calculating at compile time. Sure, it will be interesting.

Examples of code from article you can find in my Github repository.

My previous articles from “.CPP files” series are: