1 / 11

Templates

Templates. An introduction. Simple Template Functions. template <typename T> T max(T x, T y) { if (x > y) { return x; } else { return y; } } int main(void) { int x = 0; cout << max(x, ++x); // prints 1 cout << x; // prints 1 string s = “hello”; string t = “world”;

dsalvador
Download Presentation

Templates

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Templates An introduction

  2. Simple Template Functions template <typename T> T max(T x, T y) { if (x > y) { return x; } else { return y; } } int main(void) { int x = 0; cout << max(x, ++x); // prints 1 cout << x; // prints 1 string s = “hello”; string t = “world”; cout << max(s, t); // prints “world” }

  3. What’s all this? • Templates have ugly syntax. Get used to it, and on an exam, be able to “get in the ballpark” of the correct syntax. • Conceptually, templates are a lot like macros, just without the unpleasant side effects. • When you see a template, or use a template, think “text substitution” and you’ll be close

  4. Template Instantiation • A template definition is a recipe that the compiler can use to generate a function (or a class, more on that later) • The compiler will not use this recipe unless/until you instantiate the template. • At that point, the compiler goes and performs the text substitution you asked for, and then compiles the newly generated function as if you’d written that function yourself. • What happens if I instantiate the same template multiple different ways? • Well, with function overloading, we just get two or more functions with the same name, but with different arguments!

  5. Example (template definition) template <typename T, typename U> T max(T x, T y) { if (x < y) { return y; } else { return x; } } • “T” is the template parameter. Since the “T” is specified as a “typename” (i.e., the name of some type), then “T” can be replaced by any type (e.g., “int” or “string”). T can NOT be replaced by any arbitrary text, just by a type. • We have “defined” this template, which means the compiler now knows the recipe. But there is no machine code for the max function yet. The compiler won’t actually compile the max function until we instantiate it. • The compiler does do some preliminary syntax checking, so you can get compiler errors in your template definitions even if you don’t instantiate them.

  6. Example (instantiations) int main(void) { int x = 3; x = max(x, 5); // instantiation #1 double y = max(1.0, 5.0); // instantitation #2 y = max(y, y + 1); // not a new instantiation y = max(x, y); // uh oh! Ambiguous y = max<double>(x, y); // OK, the choice for T is explicitly “double” } • For the first instantiation, the compiler can easily guess that “T” should be “int” • For the second instantiation, it is also obvious that “T” should be “double” (floating point constants are double) • The compiler instantiates a different version of the template for each distinct binding of T that you use (i.e., one time for int one time for double), not each time you call the function. • Since both arguments to max are supposed to be the same type (T), the compiler can’t figure out what to do with the ambiguous line, should T be int (convert y) or should T be double (convert x). • We can remove the ambiguity in a few ways, the most certain is to simply tell the compiler what argument you want for the “type paremeter” T.

  7. Template Classes • C++ also provides template classes. • Virtually any “data structure” (AKA “collection”, AKA “container”) will be implemented in C++ as a template • The type of data stored in the structure is really not at all relevant to the data structure itself. • Template classes get “defined” and “instantiated” in analogous ways to template functions with the following caveats • The compiler will never guess at the template argument for a template class, you must always explicitly tell the compiler “what T is”. • Classes cannot be “overloaded”, but the compiler will permit you to instantiate the same template class in multiple ways. • Each distinct instantiation results in a completely distinct class! (with its own copy of the static data members, for example). • The member functions in a template class are template functions (oh, how confusing!)

  8. An example template <typename T> class Foo { T x; static int count; public: Foo() { x = 0; count += 1; } T getX(void) { return x; } int howMany(void) { return count; } }; template <typename T> int Foo<T>::count = 0; int main(void) { Foo<int> a; cout << a.getX() << endl; // prints 0 Foo<int> b; cout << b.count() << endl; // prints 2 Foo<double> c; cout << c.count() << endl; // prints 1 }

  9. A Useful Example (abridged) template <typename T> class vector { public: void push_back(T); void pop_back(void); T& operator[](int k); explicit vector(int initial_capacity=8); private: T* data; int length; int capacity; void expand(void); // increase capacity };

  10. Member functions are template functions, ugh. template <typename T> vector<T>::vector(int init_cap) { capacity = init_cap; data = new T[capacity]; length = 0; } template <typename T> void vector<T>::push_back(T x) { if (capacity == length) { expand(); } data[length] = x; length += 1; } template <typename T> void vector<T>::expand(void) { capacity *= 2; T* new_data = new T[capacity]; for (int k = 0; k < length; k += 1) { new_data[k] = data[k]; } delete[] data; data = new_data; }

  11. Templates and .h files • C++ programs (just like C) are intended to be “separately compiled”. • Each module can be compiled independently and then linked together at the end to form the executable program. • This is nice for large development teams. • Type definitions and function declarations that are “public” (i.e., used by more than one module in the system) are usually placed into a .h file • Any module that needs to know about these functions or types simply #includes the .h file. • When that module is compiled, the compiler checks the syntax by which you are calling those functions, but the compiler doesn’t actually generate machine code for those functions – i.e., the compiler uses the .h file just to make sure the modules will “interoperate”. • BUT templates require that the compiler instantiate them (or else there’s no machine code to interoperate with). And the compiler won’t know which templates to instantiate (or how to instantiate them) until it looks at all the other modules in the project. • In practice this means that the entire template (not just declarations) must be placed into the .h file. • If you’re writing a template class, you might consider just accepting this, and expanding all your member functions in place (inside the class definition).

More Related