Topical Information

The purpose of this quiz is to give you a chance to focus your knowledge of making template classes in C++.

Quiz Information

Questions

  1. Given the class below, show how you might usefully make it into a template.

        class Greater
        {
        public:
            bool operator () (long x, long y) const { return x > y; }
        };
    
    
        template <CompType>
        class Greater
        {
        public:
            bool operator () (const CompType & x, const CompType & y) const
            {
                return x > y;
            }
        };
    
    
  2. When making a class into a template, the class' name is no longer the name of the data type. What is the data type's official name? What about after you've instantiated it to create an object: what is the type of that object?

    Use the above class as an illustrative example.

    
        The name of the type is now the class name augmented with angle brackets
        and the template typename(s) inside them.
    
        For example, in the first question, the type isn't Greater but rather
        Greater<CompType>.
    
        After the class has been instantiated, the angle brackets are filled with
        the instantiation type.  So the type of this object:
    
            Greater<double> comp_dbl;
    
        is going to be Greater<double>.
    
    
  3.  
    TRUE   FALSE   template classes can easily be separated into interface and implementation to form a library.
    TRUE   FALSE   Instantiating a template class doesn't require any knowledge on the compiler's part of the definitions of the class' methods.
    TRUE   FALSE   This is because the only types that can be filled into the template are built-in types. Other classes cannot be used to fill in the data type blank of a template class.
    TRUE   FALSE   When defining the (non-inline) methods of a class, the type to the left of the scope operator must represent the template class' data type name — not the simple class name.
  4. Show the steps taken by the compiler to test instantiation of the following template class. (Hint: Requirements list..? Each type..? Operations used..?) (Note: some attempted instantiations are given but they are there just to guide you. You needn't actually show if they work or their instantiated names. It would be nice and good practice for you, but not necessary.)

        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; }
        };
    
        // potential instantiations
        Sum<double,double> s_dd;
        Sum<double,long> s_dl(10);
        Sum<Date,long> s_Dl;
        Sum<Complex,Complex> s_CC = 0.0;
        Sum<string,char> s_Sc;
    
    
        SumType:  needs:
                  i) assignment from ItemType
                 ii) assignment from itself
                iii) += from ItemType
                 iv) copy construction
        ItemType:  needs:
                   i) default construction
    
        s_dd:  SumType as double, ItemType as double:
    
               ST: i) double = double, check
                  ii) double = double, check
                 iii) double += double, check
                  iv) copy double, check
               IT: i) default construct double, check (not normally used, but there)
    
        s_dl(10):  SumType as double, ItemType as long:
    
               ST: i) double = long, check (warnings on 64-bit long machines)
                  ii) double = double, check
                 iii) double += long, check (warnings on 64-bit long machines)
                  iv) copy double, check
               IT: i) default construct long, check (not normally used, but there)
    
        s_Dl:  SumType as Date, ItemType as long:
    
               ST: i) Date = long, check (this should be a basic constructor)
                  ii) Date = Date, check
                 iii) Date += long, check (probably, if designed well)
                  iv) copy Date, check
               IT: i) default construct long, check (not normally used, but there)
    
        s_Sc:  SumType as string, ItemType as char:
    
               ST: i) string = char, fails (this should be a basic constructor,
                                            but you have to precede the char with
                                            a count)
                  ii) string = string, check
                 iii) string += char, check
                  iv) copy string, check
               IT: i) default construct char, check (not normally used, but there)
    
    
  5. Explain the strange three-stage syntax involved in making a function a friend of a template class.

    
        i) declare the template class
       ii) declare the function to make friends with
      iii) inside the template class declare your friendship with the other
           function; follow the name with empty angle brackets to remind the compiler
           that this is the templated function declared earlier
    
    
  6. Show the interface, implementation, and definition files for the following template class. (You must have at least one definition not inline.)

        /*
         * A Pair is of the form:  (x,y) or [x..y] or { x  y }.
         *
         * In general, there is a prelude symbol, a separator
         * symbol, a postlude symbol, in addition to the two
         * data items themselves.
         */
        template <typename FirstType, typename SecondType,
                     typename DescType>
        class Pair
        {
            FirstType first;
            SecondType second;
            DescType pre, sep, post;
        public:
            Pair(void);
            Pair(const FirstType & f, const SecondType & s);
            Pair(const FirstType & f, const SecondType & s,
                 const DescType & Pre, const DescType & Sep,
                 const DescType & Post);
            Pair(const Pair & p);
            FirstType get_first(void) const;
            SecondType get_second(void) const;
            void set_first(const FirstType & f);
            void set_second(const SecondType & s);
            void set_prelude(const DescType & d);
            void set_separator(const DescType & d);
            void set_postlude(const DescType & d);
            friend ostream & operator << (ostream & out, const Pair & p);
            friend istream & operator >> (istream & in, Pair & p);
        };
    
    
        The interface file (pair.h) would be almost the above except for these
        lines around it:
    
            #ifndef PAIR_H_INC
            #define PAIR_H_INC
    
            template <typename FirstType, typename SecondType,
                         typename DescType>
            class Pair;
    
            template <typename FirstType, typename SecondType,
                         typename DescType>
            ostream & operator << (ostream & out,
                                             const Pair<FirstType, SecondType,
                                                           DescType> & p);
    
            template <typename FirstType, typename SecondType,
                         typename DescType>
            istream & operator >> (istream & in,
                                             Pair<FirstType, SecondType,
                                                     DescType> & p);
    
            // class definition goes here
            // add <> after each friend operator's name inside:
            //friend ostream & operator << <> (ostream & out, const Pair & p);
            //friend istream & operator >> <> (istream & in, Pair & p);
    
            #ifdef TEMPL_CANT_SEP
                #include "pair.defn"
            #endif
    
            #endif
    
        The implementation file (pair.cpp) would be nearly empty consisting only of:
    
            #ifndef TEMPL_CANT_SEP
            #include "pair.h"
            #include "pair.defn"
            #endif
    
        The definitions file (pair.defn) would be all the member functions' and
        friends' definitions that we didn't decide to inline.  Here I've made just
        the default constructor non-inline for exposition of the idea:
    
            Pair<FirstType, SecondType, DescType>::Pair(void)
                : first{}, second{}, pre{}, sep{}, post{}
            {
            }
    
        Note that there are no #includes here and no using directive allow as it
        might be #include'd into the .h file!
    
        The other functions would have been inline'd inside the definition in the
        interface file.
    
    
  7. Describe the two methods that can be used to include a template class library in an application when the compiler has not yet realized how to separate templates into multiple files. How do you decide which method to use? Which do you feel is better?

    
        We can either use a #define before each #include of the .h file:
    
            #define TEMPL_CANT_SEP
            #include "pair.h"
    
        Or, we could use the -D command-line parameter to define the symbol we've
        chosen for all separately compiled units:
    
            CPP -DTEMPL_CANT_SEP main_app other_lib something_else
    
        If you are using the template library in multiple other files, it is far
        easier to use the -D on the command-line once.  But if just doing a one-off
        use, the #define method can be easier and clearer.