Search

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
Index
13.8 -- Partial template specialization for pointers

16 comments to 13.x — Chapter 13 comprehensive quiz

  • 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.
    -Jen

    • 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.

    Mauricio

    • 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 C++ code inside [code][/code] tags to use the syntax highlighter