Advanced Software Engineering with C++ Templates Templates Thomas Gschwind <thg at zurich dot ibm dot com>
Templates Polymorphisms Specialization Declaration and Use Classes and Members Ambiguities An Example (pvector) Th. Gschwind. Advanced Software Engineering with C++ Templates. 83
Types of Polymorphisms “Ad - hoc” • Overloading • Statically resolved by the compiler (using argument types) Dynamic • Using virtual member functions • Method to be invoked identified during run-time (using the virtual method table) Static or Parametric • Using templates • Function to be invoked identified statically • Concrete Functions/Classes are generated for the individual parameter types Th. Gschwind. Advanced Software Engineering with C++ Templates. 84
Templates – Why? Writing gcm, lcm, and swap for all kinds of types is tedious We want to define the function once and use it for all types possible • Sort of like Lisp, Smalltalk, Python, Ruby, you name it… • Just more efficiently Th. Gschwind. Advanced Software Engineering with C++ Templates. 85
Templates: Declaration and Definition Allow the use of the same function/class for different types The types become new compile-time parameters • Types need to implement the routines used by the template The definition must be available to the compiler Are checked and resolved statically (during compile time) • Function calls can be resolved during compilation time Support generic programming • Many functions are the same independently of the data type This is “ old style ”, one should use typename template<class T> instead but some people still prefer class. inline T min(T a, T b) { If you use an antiquated C++ compiler you may return a<b ? a : b; have to use class. } Th. Gschwind. Advanced Software Engineering with C++ Templates. 86
Templates: Use Are invoked like any other function (mostly) template < typename T> inline T min(T a, T b) { return a<b?a:b; } const double pi=3.141596; void f() { min(2.718282, 1.0); min('a', 'z'); min(1, 26); min(pi, 2.718282); min('a', 26); min(2.718282, 1); } Th. Gschwind. Advanced Software Engineering with C++ Templates. 89
Templates: Use template < typename T> template < typename T> inline T min(T a, T b) { inline T min(T a, T b) { return a<b?a:b; return a<b?a:b; } } const double pi=3.141596; const double pi=3.141596; void f() { void f() { min(2.718282, 1.0); min(2.718282, 1.0); // ok min('a', 'z'); min('a', 'z'); // ok min(1, 26); min(1, 26); // ok min(pi, 2.718282); min(pi, 2.718282); // ok min('a', 26); min('a', 26); // error, ambiguous min(2.718282, 1); min(2.718282, 1); // error, ambiguous } } Template parameters must be unambiguously resolved Otherwise, the ambiguity needs to be resolved manually Th. Gschwind. Advanced Software Engineering with C++ Templates. 90
Templates: Resolving Ambiguities Unlike for “normal” functions, there is no implicit conversion for templates Explicit • If necessary min<int>('a', 26); • Or even if unnecessary min<const double>(pi, 2.718282); Th. Gschwind. Advanced Software Engineering with C++ Templates. 92
Mixing Templates and Non-Templates Templates and non-templates can be mixed Can define a template-based function min And define a non template-based function min at the same time Non-templates are preferred over templates if no type conversion necessary template < class T> inline T min(T a, T b) { return a<b ? a : b; } inline double min(double a, double b) { return a<b ? a : b; } Th. Gschwind. Advanced Software Engineering with C++ Templates. 93
Templates: Resolving Ambiguities (cont‘d) We can create separate helper functions • Helper functions may be based on the underlying template inline int min( int x, int y) { return min< int >(x,y); } inline double min( double x, double y) { return min< double >(x,y); } This approach not only looks tedious but is also error- prone, clumsy, … Th. Gschwind. Advanced Software Engineering with C++ Templates. 94
min Template – A Problem? We have seen it works fine with numbers and characters What about C-style strings? cout << min("Hello", "World") << endl; The above will compare the addresses where the strings are stored • It will return the string with the smaller address This is not what the typical developer wants … For strings it would be better to use a lexicographical comparison such as strcmp … Th. Gschwind. Advanced Software Engineering with C++ Templates. 95
Specialization ( 1 st Attempt ) Templates and non-templates can be mixed Define a non template-based function min for C strings template < typename T> inline T min(T a, T b) { return a<b ? a : b; } inline char *min( char *a, char *b) { return strcmp(a,b)<0 ? a : b; } inline const char *min( const char *a, const char *b) { return strcmp(a,b)<0 ? a : b; } #include "min.h" void foo(char *x, char *y, const char *z) { cout << min(x,y) << endl; // yes cout << min(x,z) << endl; // yes cout << min<const char*>(x,z) << endl; // compiles but wrong } We are asking for the template, so we get the template … Th. Gschwind. Advanced Software Engineering with C++ Templates. 96
Template Specialization ( 2 nd and Final Attempt ) C++ allows us to specialize an existing template for specific types template < typename T> inline T min(T a, T b) { return a<b ? a : b; } template<> inline char *min<char *>(char *a, char *b) { return strcmp(a,b)<0 ? a : b; } template<> inline char *min<const char *>(const char *a, const char *b) { return strcmp(a,b)<0 ? a : b; } Compiler error; as we discussed, there is no #include "min.h" implicit parameter void foo(char *x, char *y, const char *z) { conversions for templates. cout << min(x,y) << endl; // yes cout << min(x,z) << endl; // error cout << min<const char*>(x,z) << endl; // yes } Th. Gschwind. Advanced Software Engineering with C++ Templates. 97
Templates: Classes and Members Works exactly the same Simply put template <typename T, typename U, …> in front of the declaration It is even OK, to introduce new template parameters for individual member functions Th. Gschwind. Advanced Software Engineering with C++ Templates. 98
A Persistent pvector Class We want to implement a persistent version of C++’s vector class Reads all elements from a file in the constructor Writes all elements back to the file in the destructor template < typename T> class pvector { string filename; vector<T> v; … public : pvector(string fname) : filename(fname) { readvector(); } ~pvector() { writevector(); } void push_back( const T &el) { v.push_back(el); } void pop_back() { v.pop_back(); } … Th. Gschwind. Advanced Software Engineering with C++ Templates. 99
A Persistent pvector Class (cont’d) template < typename T> class pvector { string filename; vector<T> v; void readvector() { ifstream ifs(filename); for (;;) { T x; ifs >> x; if(!ifs.good()) break; v.push_back(x); } } void writevector() { ofstream ofs(filename); typename vector<T>::iterator fst=v.begin(), lst=v.end(); while (fst!=lst) ofs << *fst++ << endl; } OR starting with C++11, simply: for ( const T &elem : v) ofs << elem << endl; … Th. Gschwind. Advanced Software Engineering with C++ Templates. 100
A Persistent pvector Class (cont’d) What happens if we pass the pvector around? void foo(pvector< int > pv) { if (pv.size()>0) cout << pv[0] << endl; pv.push_back(17); } int main( int argc, char *argv[]) { pvector< int > pv("/tmp/pvector-int.txt"); foo(pv); } Hence, maybe we want to disable the copy-constructor for pvector<T> Th. Gschwind. Advanced Software Engineering with C++ Templates. 101
Advanced Software Engineering with C++ Templates Separate Compilation Thomas Gschwind <thg at zurich dot ibm dot com>
Separate Compilation C++ versus Java Variables Routines (Functions & Operators) Types (Structures, Classes) Makefiles Th. Gschwind. Advanced Software Engineering with C++ Templates. 103
Separate Compilation Why? • Having only one source file is unrealistic • Break the code up into its logical structure • Reduction of compile time • Only changed parts need to be recompiled How? • Use multiple source files • Need to know what information about functions and variables “used” from other files Th. Gschwind. Advanced Software Engineering with C++ Templates. 104
Separate Compilation in Java Each Java file is compiled into a class file If a Java class invokes a method of another class, the compiler consults that other class file to • Determine whether the class provides the requested method • Determine whether a class file implements a given interface • etc. • Hence, the .class file contains the entire interface That’s why in Java, the compiler needs the class path Finally, all class files are loaded by the Java Virtual Machine (and “linked”) Java source code can be reconstructed from .class file (see Java Decompiler: jd, jad) Th. Gschwind. Advanced Software Engineering with C++ Templates. 105
Recommend
More recommend