Define instantiation.
Write and test your own versions of the compare functions.
Call your compare function on two Sales_data objects to see how your compiler handles errors during instantiation.
Write a template that acts like the library find algorithm. The function will need two template type parameters, one to represent the function’s iterator parameters and the other for the type of the value. Use your function to find a given value in a vector and in a list.
Write a template version of the print function from § 6.2.4 (p. 217) that takes a reference to an array and can handle arrays of any size and any element type.
How do you think the library begin and end functions that take an array argument work? Define your own versions of these functions.
Write a constexpr template that returns the size of a given array.
In the “Key Concept” box on page 108, we noted that as a matter of habit C++ programmers prefer using != to using <. Explain the rationale for this habit.
What is a function template? What is a class template?
What happens when a class template is instantiated?
The following definition of List is incorrect. How would you fix it?
template <typename elemType> class ListItem;
template <typename elemType> class List {
public:
List<elemType>();
List<elemType>(const List<elemType> &);
List<elemType>& operator=(const List<elemType> &);
~List();
void insert(ListItem *ptr, elemType value);
private:
ListItem *front, *end;
};
Write your own version of the Blob and BlobPtr templates. including the various const members that were not shown in the text.
Explain which kind of friendship you chose for the equality and relational operators for BlobPtr.
Write a Screen class template that uses nontype parameters to define the height and width of the Screen.
Implement input and output operators for your Screen template. Which, if any, friends are necessary in class Screen to make the input and output operators work? Explain why each friend declaration, if any, was needed.
Rewrite the StrVec class (§ 13.5, p. 526) as a template named Vec.
What, if any, are the differences between a type parameter that is declared as a typename and one that is declared as a class? When must typename be used?
Explain each of the following function template declarations and identify whether any are illegal. Correct each error that you find.
(a) template <typename T, U, typename V> void f1(T, U, V);
(b) template <typename T> T f2(int &T);
(c) inline template <typename T> T foo(T, unsigned int*);
(d) template <typename T> f4(T, T);
(e) typedef char Ctype;
template <typename Ctype> Ctype f5(Ctype a);
Write a function that takes a reference to a container and prints the elements in that container. Use the container’s size_type and size members to control the loop that prints the elements.
Rewrite the function from the previous exercise to use iterators returned from begin and end to control the loop.
Write your own version of DebugDelete.
Revise your TextQuery programs from § 12.3 (p. 484) so that the shared_ptr members use a DebugDelete as their deleter (§ 12.1.4, p. 468).
Predict when the call operator will be executed in your main query program. If your expectations and what happens differ, be sure you understand why.
Add a constructor that takes two iterators to your Blob template.
Explain the meaning of these declarations:
extern template class vector<string>;
template class vector<Sales_data>;
Assuming NoDefault is a class that does not have a default constructor, can we explicitly instantiate vector? If not, why not?
For each labeled statement explain what, if any, instantiations happen. If a template is instantiated, explain why; if not, explain why not.
template <typename T> class Stack { };
void f1(Stack<char>); // (a)
class Exercise {
Stack<double> &rsd; // (b)
Stack<int> si; // (c)
};
int main() {
Stack<char> *sc; // (d)
f1(*sc); // (e)
int iObj = sizeof(Stack< string >); // (f)
}
Write your own versions of shared_ptr and unique_ptr.
Revise your Blob class to use your version of shared_ptr rather than the library version.
Rerun some of your programs to verify your shared_ptr and revised Blob classes. (Note: Implementing the weak_ptr type is beyond the scope of this Primer, so you will not be able to use the BlobPtr class with your revised Blob.)
Explain how the compiler might inline the call to the deleter if we used DebugDelete with unique_ptr.
What happens during template argument deduction?
Name two type conversions allowed on function arguments involved in template argument deduction.
Given only the following code, explain whether each of these calls is legal. If so, what is the type of T? If not, why not?
template <class T> int compare(const T&, const T&);
(a) compare("hi", "world"); (b) compare("bye", "dad");
Which, if any, of the following calls are errors? If the call is legal, what is the type of T? If the call is not legal, what is the problem?
template <typename T> T calc(T, int);
template <typename T> T fcn(T, T);
double d;
float f;
char c;
(a) calc(c, ’c’);
(b) calc(d, f);
(c) fcn(c, ’c’);
(d) fcn(d, f);
What happens in the following calls:
template <typename T> f1(T, T);
template <typename T1, typename T2) f2(T1, T2);
int i = 0, j = 42, *p1 = &i, *p2 = &j;
const int *cp1 = &i, *cp2 = &j;
(a) f1(p1, p2);
(b) f2(p1, p2);
(c) f1(cp1, cp2);
(d) f2(cp1, cp2);
(e) f1(p1, cp1);
(f) f2(p1, cp1);
The library max function has two function parameters and returns the larger of its arguments. This function has one template type parameter. Could you call max passing it an int and a double? If so, how? If not, why not?
When we call make_shared (§ 12.1.1, p. 451), we have to provide an explicit template argument. Explain why that argument is needed and how it is used.
Use an explicit template argument to make it sensible to pass two string literals to the original version of compare from § 16.1.1 (p. 652).
Is the following function legal? If not, why not? If it is legal, what, if any, are the restrictions on the argument type(s) that can be passed, and what is the return type?
template <typename It>
auto fcn3(It beg, It end) -> decltype(*beg + 0)
{
// process the range
return *beg; // return a copy of an element from the range
}
Write a version of sum with a return type that is guaranteed to be large enough to hold the result of the addition.
Determine the type of T and of val in each of the following calls:
template <typename T> void g(T&& val);
int i = 0; const int ci = i;
(a) g(i);
(b) g(ci);
(c) g(i * ci);
Using the function defined in the previous exercise, what would the template parameter of g be if we called g(i = ci)?
Using the same three calls as in the first exercise, determine the types for T if g’s function parameter is declared as T (not T&&). What if g’s function parameter is const T&?
Given the following template, explain what happens if we call g on a literal value such as 42. What if we call g on a variable of type int?
template <typename T> void g(T&& val) { vector<T> v; }
Explain this loop from StrVec::reallocate in § 13.5 (p. 530):
for (size_t i = 0; i != size(); ++i)
alloc.construct(dest++, std::move(*elem++));
Write your own version of the flip function and test it by calling functions that have lvalue and rvalue reference parameters.
Write your own versions of the debug_rep functions.
Explain what happens in each of the following calls:
template <typename T> void f(T);
template <typename T> void f(const T*);
template <typename T> void g(T);
template <typename T> void g(T*);
int i = 42, *p = &i;
const int ci = 0, *p2 = &ci;
g(42);
g(p);
g(ci);
g(p2);
f(42);
f(p);
f(ci);
f(p2);
Define the functions from the previous exercise so that they print an identifying message. Run the code from that exercise. If the calls behave differently from what you expected, make sure you understand why.
Determine what sizeof...(Args) and sizeof...(rest) return for each call to foo in this section.
Write a program to check your answer to the previous question.
Write your own version of the print functions and test them by printing one, two, and five arguments, each of which should have different types.
What happens if we call print on a type that doesn’t have an << operator?
Explain how the variadic version of print would execute if we declared the nonvariadic version of print after the definition of the variadic version.
Write and test a variadic version of errorMsg.
Compare your variadic version of errorMsg to the error_msg function in § 6.2.6 (p. 220). What are the advantages and disadvantages of each approach?
Write the emplace_back function for your StrVec class and for the Vec class that you wrote for the exercises in § 16.1.2 (p. 668).
Assuming s is a string, explain svec.emplace_back(s).
Explain how make_shared (§ 12.1.1, p. 451) works.
Define your own version of make_shared.
Define your own version of hash<Sales_data> and define an unordered_multiset of Sales_data objects. Put several transactions into the container and print its contents.
Define a function template to count the number of occurrences of a given value in a vector. Test your program by passing it a vector of doubles, a vector of ints, and a vector of strings.
Write a specialized version of the template from the previous exercise to handle vector<const char*> and a program that uses this specialization.
In § 16.3 (p. 698) we defined overloaded two versions of debug_rep one had a const char* and the other a char* parameter. Rewrite these functions as specializations.
What are the advantages and disadvantages of overloading these debug_rep functions as compared to defining specializations?
Would defining these specializations affect function matching for debug_rep? If so, how? If not, why not?