Exercises






Exercises

Exercise 1

One of the biggest difficulties in writing code that uses heavily templatized types, such as tuple, is deciphering the messages that your compiler and your library implementation produce when your code has an error.

For each of the following errors, write a simple test case containing the error, and try to compile it. In the error messages, look for the key words that relate to the error in the code. This will make developing code that uses tuple much easier.

  1. Attempting default construction of a tuple object when one or more of the element types does not have a default constructor

  2. Attempting copy construction of a tuple<T> object from a tuple<U> object when objects of type U are not convertible to type T

  3. Attempting assignment of a tuple<T> object from a tuple<U> object when objects of type U are not convertible to type T

  4. Attempting copy construction or assignment to a tuple object from a tuple object with a different number of elements

  5. Attempting to call get with an index that is greater than the number of elements in the tuple argument

Exercise 2

Write and compile a source file that defines the following types:

  1. tuple0, a type that is a synonym for a tuple specialization that holds no elements

  2. tuple1, a type that is a synonym for a tuple specialization that holds one element, of type long double

  3. tuple2, a type that is a synonym for a tuple specialization that holds two elements: the first of type long double and the second of type reference to unsigned long

  4. tuple7, a type that is a synonym for a tuple specialization that holds elements of the following types: char, short, int, long, float, double, long double

Exercise 3

Write a program that creates objects of type tuple<unsigned char, unsigned char, unsigned char>[4] in three ways and displays their stored values. Do this in two steps:

[4] A tuple holding int values is more natural, but technically, you can't copy or display uninitialized values of integral types other than the three forms of char in portable code. Although this is rarely a problem in practice, the behavior of a program that does this is not defined by the C++ standard.

  1. Write a function named show that takes an argument of type const tuple<unsigned char, unsigned char, unsigned char>& and displays the three values that it holds. Use the templates get<0>, get<1>, and get<2> to get the values.

  2. In the main function, create the objects and pass them to show.

Exercise 4

Write a program that creates three auto variables of type int, all initialized to 0, and an auto object of type tuple<int&, int&, int&> that holds references to the three auto variables. Use the tuple object to show the values of the auto variables. Now change the values of the auto variables.

  1. Write three statements that use the tuple object to change the values of the three auto variables one at a time to 1, 2, and 3. Use the tuple object to show the new values.

  2. Write a single statement that uses the tuple object to change the values of the three auto variables to 4, 5, and 6. Show the new values of the auto variables. Hint: Use make_tuple.

  3. Write a single statement that creates a temporary object of type tuple<int, int, int> holding the values 7, 8, and 9 and assigns the values held in that tuple object to the three auto variables. Show the new values of the auto variables. Hint: Use a temporary object of type tuple<int&, int&, int&> to change the values of the three auto variables.

  4. Write a single statement that creates a temporary object of type tuple<int, int, int> holding the values 10, 11, and 12 and assigns the first and third values held in that tuple object to the first and third auto variables. Show the new values of the auto variables. Hint: Use tie.

Exercise 5

Write a program that shows the properties of several tuple instances.

  1. Write a function template that can be called with a tuple object holding an arbitrary number of elements that shows how many elements the object holds. Use this function to show the sizes of several tuple types. Hint: To write a function template that takes only tuple instances of various sizes, you'd have to write a separate function for each possible size. That's tedious and not particularly interesting. Instead, write a function template that takes an argument of any type and assumes that the type of the argument is, in fact, a tuple instance.

  2. Write a function template that can be called with a tuple object holding two elements that shows the types of the elements, using typeid::name. Use this function to show the types of the elements in several tuple instances.

Exercise 6

Consider the following objects:

tuple<int, int, int> t0 (1, 2, 3);
tuple<double, double, double> t1 (1.0, 2.0, 3.0);
tuple<double, double, double> t2 (1.0, 2.1, 2.9);

  1. What should the result of each of the following comparisons be?

    1. t0 == t1

    2. t0 == t2

    3. t0 < t1

    4. t0 < t2

  2. Now write a program to create these three objects, perform each of the preceding comparisons, and report the result. Compile and run the program.

Exercise 7

Some math libraries implement the sin and cos functions by calling a single function that computes both values, then picking the appropriate result.

  1. Write the prototype for that single function, with the name sincos, taking one argument of type double and returning the two double values in a tuple object.

  2. Write a function named split that takes one argument of type double and two arguments of type double&, calls sincos, and copies the two result values into its two reference arguments, without using any tuple variables.

  3. Assume that the function sincos has three overloaded versions, one taking an argument of type float and returning values of type float, one taking an argument of type double and returning values of type double, and one taking an argument of type long double and returning values of type long double. Rewrite the function split as a template that calls the appropriate version of sincos, depending on the type of its arguments.

Exercise 8

Suppose that we want to calculate the distance from the origin to a point in one-, two-, or three-dimensional space, with the location of the point held in an appropriately sized tuple object.

  1. Write a function named distance1[5] that takes an object of type tuple<double> and returns the distance from the origin to the point in one-dimensional space.

    [5] This function could be called distance and suitably overloaded, but that would get confusing when we start talking about a template with that name later on.

  2. Write a function named distance2 that takes an object of type tuple <double, double> and returns the distance from the origin to the point in two-dimensional space.

  3. Write a function named distance3 that takes an object of type tuple<double, double, double> and returns the distance from the origin to the point in three-dimensional space.

  4. Test the three distance functions with the following values:

    1. make_tuple(1.0)

    2. make_tuple(3.0, 4.0)

    3. make_tuple(3.5, 4.5, 5.5)

  5. What happens if you call any of the distance functions with a tuple object that holds no elements?

Exercise 9

Obviously, writing a separate function for each size tuple object will get pretty tedious. Since the code is so repetitive, there ought to be a way to write a single set of function templates that can calculate the distance from the origin to a point in n-dimensional space, given a representation of the location of that point as a tuple object with n elements. With a little template metaprogramming, the solution is fairly simple, although getting to it can be confusing.

We'll need a function template named distance that takes an arbitrary type T. If we assume that T is a specialization of tuple, we know from the previous exercises that we need to compute the sum of the squares of the elements of T and take the square root of that sum. We'll do that with a helper that calculates the sum of the squares of the elements of a tuple object; distance returns the square root of the value returned by that helper.

Let's look at implementing that helper. Here's where things start to get tricky. If the tuple that we're processing has one element, it's easy: The sum of the squares of the elements is simply the square of that one element. If our tuple has more than one element, the sum of the squares of its elements is the square of its first element plus the sum of the squares of the rest of its elements. This is a typical formulation for a problem that can be solved by recursion: We have a termination rule that handles the simplest case and a recursion rule that handles complex cases in terms of simpler ones. As long as each recursion results in a simpler case, we eventually bottom out at the termination case and can combine the intermediate results to get the answer. So our helper has to handle two cases: one in which we have only one element and the other in which we have more than one element. We can find out how many elements a tuple type has with the template tuple_size, and we can pick off individual elements with get. But there's a problem here: The index that we pass to get has to be a compile-time constant. Because of the limitations of template arguments to function templates, our helper has to be a class template, not a function template.

  1. Write a declaration for the class template distance_helper. The template should take two template arguments: a value elt of type size_t and a class type T. Don't give it a body.

  2. Write a partial specialization of distance_helper whose size_t argument is 0; it should still take an arbitrary type T. The specialization should have a static member function named eval that takes an argument of type const T&, assumes that T is a tuple type, and returns the square of the element at index 0 of T. This is the termination case.

  3. Write the general version of the template distance_helper. It should have a static member function named eval that takes an argument of type const T&. The function returns the square of the element at elt added to the sum of the squares of the remaining elt - 1 elements. Use distance_helper<elt -1, T> to calculate that sum. This is the recursion rule.

  4. Now all that's left is to call distance_helper's function eval from distance. Write the function distance. Caution: distance_helper takes the index of an element; the number of elements in a tuple object is not a valid index.

  5. Test the distance function with the following values:

    1. make_tuple(1.0)

    2. make_tuple(3.0, 4.0)

    3. make_tuple(3.5, 4.5, 5.5)

  6. What happens if you call distance with a tuple object that holds no elements?



 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows