13.x — Chapter 13 comprehensive quiz

Templates allow us to write functions or classes using placeholder types, so that we can stencil out identical versions of the function or class using different types. A function or class that has been instantiated is called a function or class instance.

All template functions or classes must start with a template parameter declaration that tells the compiler that the following function or class is a template function or class. Within the template parameter declaration, the template type parameters or expression parameters are specified. Template type parameters are just placeholder types, normally named T, T1, T2, or other single letter names (e.g. S). Expression parameters are usually integral types, but can be a pointer or reference to a function, class object, or member function.

Splitting up template class definition and member function definitions doesn’t work like normal classes -- you can’t put your class definition in a header and member function definitions in a .cpp file. It’s usually best to keep all of them in a header file, with the member function definitions underneath the class.

Template specialization can be used when we want to override the default behavior from the templated function or class for a specific type. If all types are overridden, this is called full specialization. Classes also support partial specialization, where only some of the templated parameters are specialized. Functions do not support partial specialization as of C++14.

Many classes in the C++ standard library use templates, including std::array and std::vector. Templates are often used for implementing container classes, so a container can be written once and used with any appropriate type.

Quiz time

1) It’s sometimes useful to define data that travels in pairs. Write a templated class named Pair1 that allows the user to define one template type that is used for both values in the pair. The following function should work:

and print:

Pair: 5 8
Pair: 2.3 4.5

Show Solution

2) Write a Pair class that allows you to specify separate types for each of the two values in the pair.

Note: We’re naming this class differently from the previous one because C++ does not currently allow you to “overload” classes that differ only in the number or type of template parameters.

The following program should work:

and print:

Pair: 5 6.7
Pair: 2.3 4

Hint: To define a template using two different types, separate the two types by a comma in the template parameter declaration. See lesson 13.1 -- Function templates for more information.

Show Solution

3) A string-value pair is a special type of pair where the first value is always a string type, and the second value can be any type. Write a template class named StringValuePair that inherits from a partially specialized Pair class (using std::string as the first type, and allowing the user to specify the second type).

The following program should run:

and print:

Pair: Hello 5

Hint: When you call the Pair constructor from the StringValuePair constructor, don’t forget to include the template parameters as part of the Pair class name.

Show Solution

14.1 -- The need for exceptions
13.8 -- Partial template specialization for pointers

34 comments to 13.x — Chapter 13 comprehensive quiz

  • magaji::hussaini

    Hi alex/nascardriver/others...
    Are C++ casts (static_cast<>(), ..., etc) template functons?

  • Joerg

    Hi and thanks for the tutorials :D I feel like the difficulty of the quizzes has fallen down a bit since chapter 9. The time they took me to complete them is only a fraction of what the chapter 9 final quiz took to complete. Is this supposed to be like that?

    • Alex

      These later quizzes need some additional work, but I've been more focused on updating the content than the quizzes. I have it on my to-do to spend some more time on these.

  • Part 3:

  • Part 2:

  • Been a while but now here's my solution to part (1):

  • Max Dmitrachkov

    I don't uderstand "const". On the left. On the right. It's everywhere

  • Arumikaze

    Hello! I have a question about common procedure when writing templates. Is it common procedure to put the function definitions inside the class or outside?

    Is this an acceptable way to write templates?

    Thank you!

    • Hi Arumikaze!

      Unless you're having trouble with multiple classes that depend on each other, write the definitions inside the class. That way you avoid having to write/update everything twice.
      In a previous reply I told you to write definitions in source files, templates are an exception to this.

  • Michael

    Hi Alex,
    I defined StringValuePair as

    and the compiler throws out an error of undefined identifier.

    But in 13.7
    I saw this:

    and it is instantiated using this

    So what's wrong with my StringValuePari definition?

    • Alex

      I'm not sure, there isn't enough information to debug here. Did you include the string header? Did you remember the template <class S> line before the class definition, so it knows that S is a template parameter?

  • Luhan

    I still a little confused about templates with inheritance. Do you know any good source about it?

  • Brad

    In regards to the 3rd question. Omitting the template parameters for the StringVaulePair constructor member initialisation list produces the same result.


    Would it be correct to assume that this is because of the way the Base class has been defined and that omitting the template parameters should be considered bad form, in this case. While in other cases it can lead to unintended results because you need it for specifying your use of partial specialisation?

    • Alex

      A template class name that doesn't have any template parameters should default to the template parameters defined above it. Since Pair has been previously defined as Pair, Pair should resolve as Pair. However, some compilers don't handle this properly.

      This issue was covered as a defect:

  • Hardik

    How can there be REFERENCES to a FUNCTION?

  • C++ Learner

    why there is a need to write const functions also?

  • Chris

    Why do we have to define (Pair<std::string, S>(key, value)) types in the constructor of StringValuePair even after we already inherited from a defined Pair(class StringValuePair : public Pair<std::string, S>) shouldn't we be able to just call Pair(key, value) ?

    • Alex

      Not sure, the language requires it. Probably to keep the compiler simpler, so it doesn't have to make any inferences about what you mean. I also suppose you could be derived from two different templated versions of a class, in which case the compiler wouldn't be able to make an inference. I can't think of a real use case for doing something like that, but the language doesn't preclude it.

  • Jen

    Hi Alex,
    When you get a chance, would you please elaborate what differences between template<typename xx> and template<class xx> are.
    Thank you.

    • Alex

      There is almost no difference. The only difference is that if you're doing a template of templates, you have to use class (as of C++14). Otherwise class and typename work identically.

  • Hi Alex. Fooling around with the code from exercise 3 I realized something I quite not understand properly. If I remove the const from Pair constructor...

    And consequently from StringValuePair constructor...

    ... I got this error

    'StringValuePair<int>::StringValuePair(StringValuePair<int> &&)': cannot convert argument 1 from 'const char [6]' to 'std::string &'

    I understand that the program fails because "Hello" as a literal is const. Is this the reason why the program fails?

    Thank you!

    • Alex

      The const char[6] literal gets converted to a temporary std::string object, which then gets passed to the T& parameter. Both literals and temporary objects are considered rvalues. However, you can't associate an rvalue with a non-const reference, which is why the compiler is complaining. You can associate a rvalue with a const reference, which is why it works when you include the const.

  • Mauricio Mirabetti

    Alex, one conceptual question, if you please:
    On exercise 1 (by the way, the "1)" is missing on the text), I first defined the getters for "first" and "second" returning const and by value, to serve both const and non-const (p1 and p2) Pair1 objects, like this:

    Your solution returns by reference and creates two version of getters. What is the more correct or usual, two versions of getters by always returning references (your solution), or one version of getter returning const by value?

    Best regards.


    • Alex

      My first() and second() aren't getters so much as they are accessors (in that they both allow get and set). Your version is close to typical if you intend first() and second() to be read-only -- however, const reference is a better choice here, since m_first and m_second may be class types, and we want to avoid making copies of those. My versions is written more from the viewpoint that we'll allow read-only access for const objects and full read/write access for non-const objects. Allowing direct access to m_first and m_second via reference does violate encapsulation to some degree, so there's that tradeoff. Another way to go would have been to have my first() and second() return by const reference only, and then provide a setFirst() and setSecond() for non-const objects that allowed the user to set the value of m_first and m_second. That's probably the safest choice all-around.

  • Nathan

    Alex, FYI - cannot compile .h files using clang++

  • Daniel

    Hi Alex,
    One small question with quiz3.
    Copy Quiz3 to compile will get following errors:
    main_quiz3.cpp: In constructor ‘StringValuePair<S>::StringValuePair(const string&, const S&)’:
    main_quiz3.cpp:28:5: error: class ‘StringValuePair<S>’ does not have any field named ‘Pair’
       : Pair(key, value)
    main_quiz3.cpp: In instantiation of ‘StringValuePair<S>::StringValuePair(const string&, const S&) [with S = int; std::string = std::basic_string<char>]’:
    main_quiz3.cpp:35:37:   required from here
    main_quiz3.cpp:28:20: error: no matching function for call to ‘Pair<std::basic_string<char>, int>::Pair()’
       : Pair(key, value)
    main_quiz3.cpp:28:20: note: candidates are:
    main_quiz3.cpp:12:2: note: Pair<T, S>::Pair(const T&, const S&) [with T = std::basic_string<char>; S = int]
      Pair(const T& x, const S& y)
    main_quiz3.cpp:12:2: note:   candidate expects 2 arguments, 0 provided
    main_quiz3.cpp:5:7: note: Pair<std::basic_string<char>, int>::Pair(const Pair<std::basic_string<char>, int>&)
    class Pair
    main_quiz3.cpp:5:7: note:   candidate expects 1 argument, 0 provided

    change line 28 to explicitly define can pass compile.
    -> 28         : Pair<std::string, S>(key, value)

Leave a Comment

Put all code inside code tags: [code]your code here[/code]