Design Patterns in C++

Similar documents
Design Patterns in C++

Design Patterns in C++

C++ Template Meta. A basic introduction to basic C++ techniques used in template metaprogramming.

Object Oriented Software Design II

Object Oriented Software Design II

Object Oriented Software Design II

Fundamentals of Programming

template<typename T> cout << "The value is << value << endl; } void printdata(t value){

Informatica e Sistemi in Tempo Reale

Passing arguments to functions by. const member functions const arguments to a function. Function overloading and overriding Templates

Short Notes of CS201

POLYMORPHISM 2 PART Abstract Classes Static and Dynamic Casting Common Programming Errors

Templates. Giuseppe Lipari Scuola Superiore Sant Anna Pisa. June 8, 2009

CS201 - Introduction to Programming Glossary By

POLYMORPHISM 2 PART. Shared Interface. Discussions. Abstract Base Classes. Abstract Base Classes and Pure Virtual Methods EXAMPLE

Before we dive in. Preprocessing Compilation Linkage

Structuur van Computerprogramma s 2

An Introduction to Template Metaprogramming

template <typename T> // unless it s an unqualified pointer struct IsPtr<T *> { enum { r = true }; };

C++ Important Questions with Answers

Object Oriented Software Design

CS2141 Software Development using C/C++ C++ Basics

Object Oriented Software Design

Lecture-5. Miscellaneous topics Templates. W3101: Programming Languages C++ Ramana Isukapalli

Instantiation of Template class

Welcome Back. CSCI 262 Data Structures. Hello, Let s Review. Hello, Let s Review. How to Review 1/9/ Review. Here s a simple C++ program:

} else if( Ellipse *e = dynamic_cast<ellipse *>(shape) ) { } else if( Square *s = dynamic_cast<square *>(shape) ) {

Part X. Advanced C ++

C++ Programming: Polymorphism

An introduction to C++ template programming

Function Overloading

CS 251 INTERMEDIATE SOFTWARE DESIGN SPRING C ++ Basics Review part 2 Auto pointer, templates, STL algorithms

OBJECT ORIENTED PROGRAMMING USING C++

COSC 320 Exam 2 Key Spring Part 1: Hash Functions

1/29/2011 AUTO POINTER (AUTO_PTR) INTERMEDIATE SOFTWARE DESIGN SPRING delete ptr might not happen memory leak!

Polymorphism. Zimmer CSCI 330

Welcome Back. CSCI 262 Data Structures. Hello, Let s Review. Hello, Let s Review. How to Review 8/19/ Review. Here s a simple C++ program:

Lecture 2 Polymorphism, Traits, Policies, and Inheritance

Object Oriented Software Design II

Tokens, Expressions and Control Structures

Object Oriented Software Design II

Advanced Systems Programming

Object-Oriented Principles and Practice / C++

Polymorphism. Contents. Assignment to Derived Class Object. Assignment to Base Class Object

Simulating Partial Specialization

Object-Oriented Programming, Iouliia Skliarova

CSE143 Exam with answers MIDTERM #1, 1/26/2001 Problem numbering may differ from the test as given.

eingebetteter Systeme

Francesco Nidito. Programmazione Avanzata AA 2005/06

Chapter 1 INTRODUCTION SYS-ED/ COMPUTER EDUCATION TECHNIQUES, INC.

Cpt S 122 Data Structures. Templates

Template metaprograms

First of all, it is a variable, just like other variables you studied

Introduction to C++ Giuseppe Lipari April 27, Scuola Superiore Sant Anna Pisa

Creating Templates and Implementing Smart Pointers CS193D 2/27/06

Introduction to C++ Systems Programming

Basic Templates Intro

Advanced C++ 4/13/2017. The user. Types of users. Const correctness. Const declaration. This pointer and const.

Lecture 2, September 4

Topics. bool and string types input/output library functions comments memory allocation templates classes

An introduction to. Templates. Generic Programming. Good old C. Metaprogramming 4/13/2017

EL6483: Brief Overview of C Programming Language

Non-numeric types, boolean types, arithmetic. operators. Comp Sci 1570 Introduction to C++ Non-numeric types. const. Reserved words.

Object Oriented Software Design

Variables. Data Types.

III. Classes (Chap. 3)

Programming in C++: Assignment Week 8

Design Patterns in C++

Financial computing with C++

Fundamentals of Programming

What does it mean by information hiding? What are the advantages of it? {5 Marks}

Fast Introduction to Object Oriented Programming and C++

COM S 213 PRELIM EXAMINATION #2 April 26, 2001

Object Oriented Software Design II

What is Polymorphism? Quotes from Deitel & Deitel s. Why polymorphism? How? How? Polymorphism Part 1

Object Oriented Software Design II

Object Oriented Software Design

boost::enable_if Deep Down Boostimagical Fun Christian Bay and Kasper A Andersen Department of Computer Science University of Copenhagen

I m sure you have been annoyed at least once by having to type out types like this:

Before we start - Announcements: There will be a LAB TONIGHT from 5:30 6:30 in CAMP 172. In compensation, no class on Friday, Jan. 31.

Informatica e Sistemi in Tempo Reale

COMS W3101 Programming Language: C++ (Fall 2015) Ramana Isukapalli

Fundamentals of Programming

COMS W3101 Programming Language: C++ (Fall 2015) Ramana Isukapalli

Design Patterns in C++

C++ Crash Kurs. Polymorphism. Dr. Dennis Pfisterer Institut für Telematik, Universität zu Lübeck

GridKa School 2013: Effective Analysis C++ Templates

Polymorphism Part 1 1

More Functions. Pass by Value. Example: Exchange two numbers. Storage Classes. Passing Parameters by Reference. Pass by value and by reference

C The new standard

Object Oriented Software Design - II

G52CPP C++ Programming Lecture 20

Function Binding. Special thanks to: John Edwards. Randy Gaul

1d: tests knowing about bitwise fields and union/struct differences.

Agenda. The main body and cout. Fundamental data types. Declarations and definitions. Control structures

C++ Programming Lecture 7 Software Engineering Group

Stream Computing using Brook+

COMS W3101 Programming Language: C++ (Fall 2016) Ramana Isukapalli

From Java to C++ From Java to C++ CSE250 Lecture Notes Weeks 1 2, part of 3. Kenneth W. Regan University at Buffalo (SUNY) September 10, 2009

Module Operator Overloading and Type Conversion. Table of Contents

Transcription:

Design Patterns in C++ Template metaprogramming Giuseppe Lipari http://retis.sssup.it/~lipari Scuola Superiore Sant Anna Pisa April 6, 2011 G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 1 / 41 Templates as code generators A template is a way to generate code. The following program generates three functions template<typename T> void swap(t& a, T&b) { T t = a; a = b; b = t; int main() { char z = 1, w = 2; int x = 3, y = 4; double r = 5, s = 6; swap(z, w); swap(z, y); swap(r, s); void swap(char &a, char &b) { char t = a; a = b; b = t; void swap(int &a, int &b) { int t = a; a = b; b = t; void swap(double &a, double &b) { double t = a; a = b; b = t; G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 3 / 41

Template members It is also possible to make one member function a template class MyClass { public: template<class V> void accept(v &v) { v.visit(*this); The member function is not compiled if it is not used Important restriction: cannot make template virtual methods G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 4 / 41 Incomplete instantiation Remember that template classes are not generated if not used. This is also valid for members of template classes template <class T> class MyClass { T *obj; public: MyClass(T *p) : obj(p) { void call_fun() { obj->fun(); T* getptr() { return ptr; MyClass<int> my(new int(6)); cout << my.getptr() << endl; In the code above, function call_fun() is never called, so the code is correct (it would give error on a int type!) G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 5 / 41

Template template parameters It is possible to require a parameter to be a template: template <template <class Created> class CreationPolicy> class WidgetManager : public CreationPolicy<Widget> { public: void fun() { Widget *w = create(); template <class T> class DynamicCreation { public: T* create() { return new T; G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 6 / 41 Template template parameters template parameter Created can be entirely omitted template <template <class> class CreationPolicy> class WidgetManager : public CreationPolicy<Widget> { public: void fun() { Widget *w = create(); G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 7 / 41

Specialization Another important feature is template specialization Given a template with one or more parameters: we can provide special versions of the template where some of the parameter is assigned specific types // general version template<class T> class MyClass { // special version with T = int template <> class MyClass<int> { MyClass<double> m; // uses the general version MyClass<int> n; // uses the special version G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 8 / 41 Partial specialization When we have more than one type parameter, we can specialize a subset of the types // general version template<typename T, typename U> class A { // specialization on T template<typename U> class A<int, U> { // specialization on both template<> class A<int, int> { A<double, double> a; // uses general version A<int, double> b; // uses first specialization A<int, int> a; // uses second specialization G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 9 / 41

Problems Be careful with partial template specialization // general version template<typename T, typename U> class A { // specialization on T template<typename U> class A<int, U> { // specialization on U template<typename T> class A<T, int> { A<int, int> a; // Error! ambiguos G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 10 / 41 Restrictions on partial specialization Partial template specialization does not apply to functions template <class T, class U> T fun(u obj) { // the following is illegal template <class U> void fun<void, U>(U obj) { // the following is legal (overloading) template <class T> T fun(window obj) { G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 11 / 41

Integral template parameters The parameters of a template can be constant numbers instead of types By constant I mean that they are known at compile time template <unsigned n> struct Num { static const unsigned num = n; Num<5> x; Num<8> y; cout << x.num << endl; cout << y.num << endl; cout << "sizeof(num<5>) = " << sizeof(x) << endl; Note 1: the output of last instruction is 1 Note 2: we can also make calculation with n, but of course they must be solved at run-time G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 12 / 41 Specialization on numbers We can also specialize on certain numbers template <unsigned n> struct VarNum { void p() { cout << "Number is " << n << endl; template <> struct VarNum<0> { void p() { cout << "N is zero!!" << endl; G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 13 / 41

Factorial The code generation engine that is embedded in the C++ compiler can actually make some simple calculation, using recursion The key trick is combine specialization with integral parameters This is calculation made by the compiler, not at run-time! Here is how to compute the factorial template <int n> struct Fact { enum { value = n * Fact<n-1>::value template <> struct Fact<1> { enum { value = 1 cout << Fact<5>::value << endl; See the code G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 14 / 41 Very simple types C++ does not require much for defining a type The following ones are all different types struct Simple { struct AnotherSimple { struct YetAnotherSimple { Of course, you cannot do much with such types, except telling the compiler that a certain type exist at run time there is no code associated with it sizeof(simple) returns 1 G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 15 / 41

Defining types Look at this code template<typename T> struct Cont { typedef T MyType; Cont<int>::MyType aninteger = 2; Cont<double>::MyType adouble = 0.5; Cont does not contain anything, only the definition of another type, which is only used by the compiler, but not at run-time Cont<int> is not different from Simple G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 16 / 41 Mapping integers to types It is sometimes necessary generate new types from integers. Here is how to do it: template<int v> struct Int2Type { enum {value = v This template generates a new type for each integral number it is passed we will use this in the following to do a compile-time dispatch You want to select one of several functions to be called, and you want to do this selection at compile time, depending on a compile-time constant G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 18 / 41

Run-Time vs. Compile time dispatching Run-time dispatching is something that depends on the values of certain variables that are only known at run-time It can be performed by using if-then-else or switch-case statements It can also be performed using virtual functions and dynamic binding the cost of doing this is often negligible of course, you can also do run-time dispatching based on compile-time constants however this is not always possible G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 19 / 41 Selection example Suppose you are designing a container template<class T> MyContainer { You want to provide the ability to copy objects of type MyContainer by copying all contained objects to duplicated contained objects, you can call the copy constructor, but this may not be always available Suppose instead that class T provides a virtual clone() method you would like your container to be generic, i.e. a container that can be used both for objects with copy constructors (non-polymorphic), and objects with clone (polymorphic) therefore, the choice of calling one of the two functions is based on a compile-time boolean constant ispolymorphic G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 20 / 41

Run-time selection? The following code does not work: template <class T, bool ispolymorphic> class MyContainer { void function() { T *p = ; if (ispolymorphic) { T *p2 = p->clone(); else { T *p2 = new T(*p); why? G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 21 / 41 Compile-time dispatch Solution: template<class T, bool ispolymorphic> class MyContainer { private: void function(t* p, Int2Type<true>) { T *p2 = p->clone(); void function(t *p, Int2Type<false>) { T *p2 = new T(*p); public: void function(t *p) { function(p, Int2Type<isPolymorphic>()); The basic trick is that only one between the two private function will be compiled, the right one! G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 22 / 41

Type to Type Unfortunately, it is not possible to apply partial template specialization to functions You can simulate this with overload example: // creates a class by invoking the constructor, // which takes one argument template<class T, class U> T *create(const U &arg) { return new T(arg); Now, suppose you want to specialize it by using the same function on objects of class Widget, whose constructor takes two arguments, the second one must always be -1 G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 23 / 41 Special version Wrong: template<class T, class U> T *create(const U &arg) { return new T(arg); template<class U> Widget *create<widget, U>(const U &arg) { return new Widget(arg, -1); Correct: template<class T, class U> T *create(const U &arg, T) { return new T(arg); template<class U> Widget *create(const U &arg, Widget) { return new Widget(arg, -1); G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 24 / 41

Reducing overhead To eliminate the overhead of creating a dummy parameter to pass by value, we can use the following trick : template<typename T> struct Type2Type { typedef T OriginalType; template<class T, class U> T *create(const U &arg, Type2Type<T>) { return new T(arg); template<class U> Widget *create(const U &arg, Type2Type<Widget>) { return new Widget(arg, -1); string *ps = create("hello", Type2Type<string>()); Widget *pw = create("hello", Type2Type<Widget>()); G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 25 / 41 Selecting types Suppose that in MyContainer we want to store objects if the type is non-polymorphic, and pointers to objects if the type is polymorphic for simplicity, suppose that internally we use a vector what type should we give to the vector? T or T*? We can make use of a select structure template <bool flag, typename T, typename U> struct Select { typedef T Result; template<typename T, typename U> struct Select<false, T, U> { typedef U Result; G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 26 / 41

Selecting the type template <typename T, bool ispolymorphic> class MyContainer { typedef typename Select<isPolymorphic, T*, T>::Result ValueType; std::vector<valuetype> objects; G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 27 / 41 How to detect type relationship Sometimes it is important to be able to understand if two generic types T and U are in a relationship of inheritance for example, we would like to know if U derives from T this may be useful sometimes when we have to check and enforce some properties on types in our generic algorithms at compile time also, some algorithms may be optimized if an inheritance relationship exists inheritance is a special case of convertibility between pointers there are only three cases in which we can automatically convert U* to T*; T and U are the same case T is a public base class of U T is void (because any pointer can be converted to void *) So, now the problem is how to detect if an automatic conversion exists at compile time G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 29 / 41

Using sizeof sizeof() is a compile time mechanism of C/C++ to compute the size of a type since it is done at compile time, its argument is not actually executed at run-time, but it is only evaluated For example, if the argument contains a function call, it does not actually invoke the function, but it only checks its type int returnint(); // not implemented sizeof(returnint()); // equivalent to sizeof(int) sizeof() returns an integer that we can use in comparisons, so let s define two types of different size typedef char Small; class Big { char dummy[2]; G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 30 / 41 Conversion template <typename T, Typename U> class Conversion { typedef char Small; class Big { char dummy[2]; static Small Test(U); static Big Test(); static T MakeT(); public: enum { exists = sizeof(test(maket())) == sizeof(small) We try pass an object of type T to a function that takes a U or anything else; If the conversion exist, the first version is used which returns a Small G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 31 / 41

Last step We can define (also in the previous code) an additional enum value sametype and provide the following specialization template<typename T> class Conversion { public: enum { exists = true, sametype = true; #define SUPERSUBCLASS(T, U) \ (Conversion<const U*, const T*>::exists && \!Conversion<const T*, void *>::sametype) #define SUPERSUBCLASS_STRICT(T, U) \ (SUPERSUBCLASS(T, U) && \!Conversion<const U*, const T*>::sameType) G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 32 / 41 TypeList definition A type list is a simple list of any number of types (from 1 to any) At compile time the user instantiates the typelist with the desired types however, C++ does not support a variable number of template arguments Therefore, we have to simulate it the basic structure is very simple: struct NullType { template<typename H, typename T> struct TypeList { typedef H Head; typedef T Tail; G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 34 / 41

Defining typelists A few examples: // two types, int and double TypeList < int, TypeList<double, NullType> > intdoublevar; // three types, int, double and char TypeList < int, TypeList < double, TypeList<char, NullType> > > intdoublecharvar; G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 35 / 41 Obtaining types It is annoying to carry on a list in expanded form We can use defines to simplify the writing a little bit #define TYPELIST_1(t1) TypeList<t1, NullType> #define TYPELIST_2(t1, t2) TypeList<t1, TYPELIST_1(t2) > #define TYPELIST_3(t1, t2, t3) TypeList<t1, TYPELIST_2(t2, t3) > TYPELIST_3(int, double, char) intdoublecharvar; Remember: the size of variable intdoublecharvar is... 1!! so, what is the purpose of this? a typelist is not a useful class, because it does not contain code it is only useful to help the compiler to generate code it is a trick to pass types instead of values G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 36 / 41

How to use it A type list can be used to obtain the various types in the list typedef TYPELIST_3(int, double, char) ThreeTypes; ThreeTypes::Head param1; // this will be an int ThreeTypes::Tail::Head param2; // this will be a double ThreeTypes::Tail::Tail::Head param3; // this will be a char It is quite ugly, but it works: I now defined three variables with the right type Almost there, we are missing a few steps G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 37 / 41 Example Suppose I need to write the code for a structure that must contain three data members however, I do not know a-priori the type of these members I would like to write generic, template code that instantiates the structure with the right types template <typename T> struct MyStruct { T::Head param1; T::Tail::Head param2; T::Tail::Tail::Head param3; MyStruct< TYPELIST_3(int, double, char) > s; s.param1 = 5; s.param2 = 0.75; s.param3 = a ; G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 38 / 41

How to simplify type extraction template<typename H, typename T, unsigned index> struct TypeAt { typedef typename TypeAt_<typename T::Head, typename T::Tail, index-1>::result Result; // specialization for index == 0 template <typename H, typename T> struct TypeAt<H, T, 0> { typedef H Result; // if it reaches the end of the list with index > 0 template <typename H, unsigned index> struct TypeAt<H, NullType, index> { typedef NullType Result; // special case: the last element template <typename H> struct TypeAt<H, NullType, 0> { typedef H Result; #define TYPEAT(L, i) typename TypeAt<typename L::Head, \ typename L::Tail, \ i \ >::Result G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 39 / 41 How to use it Quite difficult to understand However, once it works, it s already there, you do not need to understand how it works every time you only need to know how to use it template<typename L> struct MyStruct { TYPEAT(L, 0) param1; TYPEAT(L, 1) param2; TYPEAT(L, 2) param3; MyStruct< TYPELIST_3(int, double, char) > s; s.param1 = 1; s.param2 = 0.75; s.param3 = c ; G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 40 / 41

Count elements in the typelist template<typename H, typename T> struct TypeListSize { enum { Result = TypeListSize<T::Head, T::Tail, index-1>::result + 1 template<typename H> struct TypeListSize<H, NullType> { enum { Result = 1 template<typename T> struct TypeListSize<NullType, T> { enum { Result = 0 #define TYPELISTSIZE(L) TypeListSize<L::Head, L::Tail>::Result G. Lipari (Scuola Superiore Sant Anna) Template metaprogramming April 6, 2011 41 / 41