The purpose of this quiz is to give you a chance to focus your knowledge of advanced template usage in C++.
Briefly explain the use of non-type template parameters. (Perhaps a specific example might help...
Where we normally list typenames to be specified to or deduced by the compiler, we may also place discrete types which are to be filled in with a value. This can be used, for instance, to create many classes for an array of arbitrary dimensions -- each dimensionality being its own separate class. We could also use it to build a templated swap function for C-style arrays by making the common allocated size of the two arguments the template's non-type parameter. (Of course, we'd also have to use a reference trick to bind the size to the array argument since any listed size for a 1D array argument is normally ignored by the compiler!)
Briefly describe the difference between overloading a template and specializing a template.
An overloaded template is still not instantiated but, rather, merely gives the compiler multiple blank patterns to match against. It will still choose the pattern that most specifically matches the current invocation thanks to SFINAE (Substitution Failure Is Not An Error). With specialization, however, a template has its existing typenames partially or fully filled in with specific data types. (Or its non-type parameters may be filled in with specific values.) This creates a new instantiation for the template pattern which is inherently more specific than the template itself. Either way you go, typecasting can help at the call site to make sure the right form of the function is called. This works best because it doesn't matter if the function is a template or not, the compiler just uses the right types.
Below are two designs for a templated Sum class that can add up a sequence of values to a total and then retrieve that total later. In each case, the types of the items being summed don't have to be the same as those of the sum itself. What is the difference between the two and what might the benefit of this difference be?
Consider not only adding up numbers but also concatenating strings.
template <typename SumType, typename ItemType> class Sum { SumType sum; public: Sum(const ItemType & s = ItemType()) { sum = s; } Sum(const Sum & s) { sum = s.sum; } SumType operator() (const ItemType & n) { return sum += n; } SumType operator() (void) { return sum; } void reset(const ItemType & s = ItemType()) { sum = s; return; } }; template <typename SumType> class Sum { SumType sum; public: Sum(const SumType & s = SumType()) { sum = s; } Sum(const Sum & s) { sum = s.sum; } template <typename ItemType> SumType operator() (const ItemType & n) { return sum += n; } SumType operator() (void) { return sum; } void reset(const SumType & s = SumType()) { sum = s; return; } };
The first Sum class requires all of the elements being added to the sum to be of the same type -- a homogeneous sequence. The second Sum class allows the elements being added at each step to be of different types from those before/after them -- a heterogeneous sequence. The second approach can be more flexible in cases where we want to add up numbers of different types through the course of the program or even add up both strings, C-strings, and characters at different points in a program.
If we were for some reason defining the second Sum class' summing operator() not inline, show how this would look.
template <typename SumType> template <typename ItemType> SumType Sum<SumType>::operator() (const ItemType & n) { return sum += n; } Note how we had to nest the ItemType template inside the SumType template rather than merging them together. Also note that the scope of the operator just has the SumType involved.
Now let's consider templates mixed with inheritance:
TRUE ✗ | FALSE ✓ | A base class cannot be a template class. | ||
---|---|---|---|---|
TRUE ✓ | FALSE ✗ | A derived class can be a template class. | ||
TRUE ✗ | FALSE ✓ | If we derive from a template class, the new class must be a template, too. | ||
TRUE ✗ | FALSE ✓ | If we derive from a non-template class, the new class must be a non-template, too. |
TRUE ✗ | FALSE ✓ | When a template class has static member(s), all instantiations share the same static member(s). |
---|