+ All Categories
Home > Technology > Metaprogramming

Metaprogramming

Date post: 10-May-2015
Category:
Upload: ganesh-samarthyam
View: 1,706 times
Download: 0 times
Share this document with a friend
Popular Tags:
49
Unleashing the power of C++ Templates An Introduction to Meta- programming
Transcript
Page 1: Metaprogramming

Unleashing the power of C++ Templates

An Introduction to Meta-programming

Page 2: Metaprogramming

2

Why Meta-Programming?

Page 3: Metaprogramming

3

Introduction

Generic programming becoming a dominant paradigm in C++The unexplored power of functional programming languages Higher levels of abstraction, design and reusabilityA code-generation mechanism (programs that generate programs!) Greater efficiency on what can be found at compile-time

Page 4: Metaprogramming

4

Generic Programming

Early 90s when templates were used for container<T>STL How standardization helpedDesign patterns The ability for templates to model many design patterns

directly Idea of meta-programming possibility Boost Loki Other libraries

Page 5: Metaprogramming

5

Functional programming

Functional programming is there for a long time Lambda calculus, Lisp, Scheme, Haskell… functions are treated as regular values

Functional programming advantages Idioms, patterns and techniques

Polymorphic “higher-order” functions Functions that take other functions as arguments and

returns functions! The ‘lambda’ thing Creating functions ‘on-the-fly’ is very common

TMP is inspired by functional programming

Page 6: Metaprogramming

6

Abstraction, Design and Reusability

The much hyped ‘component software’ ‘Plug-and-play’ software

Design Patterns The GoF (Gang of Four) ‘Design Patterns’ book Elements of reusable software Language independent

Library as the basis of reusable software (as opposed to frameworks)The proverbial ‘adding a level of indirection’ as a means for better reusable components

Page 7: Metaprogramming

7

Program Generating Programs

That is what TMP is all about Template is not the code that executes Generates the code that will do the actual work

Abstract the details Select the behavior Instruct the components you want to generate

Evaluate whatever is possible at compile-time

Page 8: Metaprogramming

8

Efficiency

Templates can be unimaginably powerful and efficientExecution is moved on to compile-time The compiler does the work for you instead of the

program! Higher levels of abstraction, design and reusabilityA code-generation mechanism (programs that generate programs!) Greater efficiency on what can be found at compile-time

Page 9: Metaprogramming

9

Template (tricky) Basics

Page 10: Metaprogramming

10

Parameterized Types

Templates started Stroustrup’s desire to provide "parameterized types" for containers. A simple example would be a stack:

Page 11: Metaprogramming

11

“Parameterized” Stack

template <class T> class stack{

stack(int start_size = 10);int is_empty() const;int is_full() const;// these members remain the same void push(const T& t);T& pop();// templatizing the required members

private:T* stack; // Note T* here int top_of_stack;int size;

};

Page 12: Metaprogramming

12

Comparing with Java example

Making use of Object base class Not type safe – the single biggest problem Java

programmers face after performance issues “Generic types” for typesafety – not for genericity per se

class Stack<Type> { public void push(Type t){ /* … */ }public Type pop() { /*... */ }private int topOfStack;private int size = 10;T stack []; { stack = new stack[size]; }

} Similarity of C++ templates and Java generics end here!

Page 13: Metaprogramming

13

Templates for Reusable Components

An example: Making classes non-inheritableC++ has no equivalent of Java's final (for class non-inheritable classes)

You can make destructor of base class private disallows creating objects (except in heap)

Disadvantage: imposes constraints on kind of type of allocation being done.

Page 14: Metaprogramming

14

Example: ‘Plain’ Code

class Usable;struct Usable_lock {

friend class Usable;private:

Usable_lock(){} // copy ctr also private

};struct Usable : public virtual Usable_lock{

Usable(); // copy ctr also public // ...

};

Page 15: Metaprogramming

15

Example: ‘Plain’ Code … Usable a;

class DD : public Usable { };

DD dd; // error: DD::DD() cannot access // Usable_lock::Usable_lock() // which is a private member

Page 16: Metaprogramming

16

Example: ‘Templatized’ Code

template <typename T> struct nonderivable;

template< class T > class nonderivable_base{friend T;// warning, this is non-standard!friend class nonderivable<T>;nonderivable_base(){}

nonderivable_base(const nonderivable_base&){}};

template <typename T> struct nonderivable: public virtual

nonderivable_base<T>{};

Page 17: Metaprogramming

17

Example: ‘Templatized’ Code …

class Test: nonderivable <Test> {};

Test t;// okay, you can create objects

class Deri: Test{}; // no, you can't inherit & use the object

Deri d; // Error, in-accessible base class constructor. //See, compiler won't allow you to do so.

Page 18: Metaprogramming

18

Template Template Parameters

One of the interesting properties of templates parameter can be an instantiation of the same

template. For example, vector < vector<int> >Template Template provide next level of abstraction The template (not its instance) itself can

become an argument

Page 19: Metaprogramming

19

Template Template Parameters …

template < typename type,

template <typename T, typename A> class container = std::vector, // default is vector if you don’t provide

one explicitly typename allocator = std::allocator<type> > class my_container { container<type, allocator> _container;

//instantiate template template parameter};// instantiation of my_container my_container<int, std::list> container;

Page 20: Metaprogramming

20

In many cases, you can live without it. For example,std <stack> container namespace std { template <class T, class Container = deque<T> >

class stack; }

Another example is allocator used for containers namespace std { template <class T, class Allocator = allocator<T> >

class vector; }

Template Template Parameters …

Page 21: Metaprogramming

21

Meta-Programming

Page 22: Metaprogramming

22

How it started?

Started with a mistake which led to infinite recursion in instantiating templatesInitial examples seem simple and for fun But has appeal for serious design and industrial

use Earliest documented example is by Erwin Unruh for computing Prime numbers. Initially popularized by Todd Veldhuizen Used in Blitz++

Page 23: Metaprogramming

23

Serendipity

Infinite instantiation: template <int n>struct Factorial {

static const int val = n * Factorial<n-1>::val;

};static const int val = Factorial<3>::val; aCC complains: Error 588:Template generation nesting too deep;

discovered during generation of specialization 'Factorial<(int)-251>'. You may have an infinite recursive generation.

Page 24: Metaprogramming

24

Adding Terminating Condition

template <int n>struct Factorial { static const int val = n * Factorial<n-1>::val;};

template <>struct Factorial<1> { static const int val = 1; };

const int factorial_of_3 = Factorial<3>::val;

Page 25: Metaprogramming

25

Programming Constructs

Metaprograms can be thought in terms of productions (just like recursive programs).Implementing productions in algorithms requires control flow constructs. If, do, while, for, switch… can be expressed in terms of templates (expression templates).

Page 26: Metaprogramming

26

Template for If-Then

One example: Representing If-Then-Else condition How to select a class member type based on a

condition? Say signed or a unsigned one One way to achieve this is to have a traits class and

make the selection over there using a boolean non-type parameter (basis for typetraits library).

Part of all major meta-programming libraries (Loki, Boost etc).

Page 27: Metaprogramming

27

Template for If-Then

template <typename T, bool isSigned> struct myMemberSignTrait{

typedef signed T signType; }; // selected in case isSigned is true

template <typename T, false> // partial specialization for false

struct myMemberSignTrait{typedef unsigned T signType;

}; // selected if isSigned is false

Page 28: Metaprogramming

28

Template for If-Then

template <typename T, bool isSigned> class myContainer {

typedef myMemberSignTrait<T, isSigned> memberSignTrait; typedef typename containerMemberTrait::signType signType; signType member;

// member will be signed or unsigned // depending on the isSigned bool value };

Page 29: Metaprogramming

29

Improved If-Then

Not elegant to extend (not scalable)Better to have a separate template class for doing such a selection.

template <typename T, typename F, bool isSigned> struct if_select {

typedef T type; }; // selected in case isSigned is true

// partial specialization for false template <typename T, typename F> struct if_select <typename T, typename F, false> {

typedef F type; }; // selected if isSigned is false

Page 30: Metaprogramming

30

Improved If-Then

template <typename T, bool isSigned> class myContainer {

typedef typename if_select<signed T, unsigned T, isSigned>::type signType; signType member; // ...

};

Page 31: Metaprogramming

31

Still better If-Then

template <bool isSigned> struct if_cond {

template<typename T, typename F>struct then_select {

typedef T type; };

}; // selected in case isSigned is true

template <bool isSigned> // partial specialization for false struct if_select <false> {

template<typename T, typename F>struct then_select {

typedef F type; };

}; // selected in case isSigned is true

Page 32: Metaprogramming

32

Still better If-Then

template <typename T, bool isSigned> class myContainer {

typedef typename if_cond<isSigned>::template then_select<signed T, unsigned T>::type signType;

signType member; // ...

};

Page 33: Metaprogramming

33

Usage Example – if_select

class CompactingGC {void GC() { … }

};class MarkAndSweepGC {

void GC() { … }};

If_cond <GC == COPY, CopyingGC, MarkAndSweepGC>::value gc;

gc.GC();

Page 34: Metaprogramming

34

Another Example- isPointer

template <typename T>class type_traits{

template <class U> struct pointer_traits{static const int result = false;

}// specialization for pointer type template <class U *> struct pointer_traits{

static const int result = true; }

public:static const int is_pointer = pointer_traits<T>:: result;

}; // const bool is_ptr =

type_traits<someTypedef>::is_pointer;

Page 35: Metaprogramming

35

Application of meta-programming

Page 36: Metaprogramming

36

Conversion Check Tool

template <class T, class 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) };

};

Page 37: Metaprogramming

37

Unrolling vector addition

inline void addVect(int size, double* a, double* b, double* c) {

while (size--) *c++ = *a++ + *b++;}

Page 38: Metaprogramming

38

Template Unrollingtemplate<int size>inline void addVect(double* a, double* b,

double* c) { *c = *a + *b; addVect<size-1>(a+1, b+1, c+1);}template<>inline void addVect(double* a, double* b,

double* c) { }

addVect<3>(a, b, c);

Page 39: Metaprogramming

39

Effect of unrolling

addVect<3>(a, b, c); *c = *a + *b; addVect<2>(a+1, b+1, c+1); *(c+1) = *(a+1) + *(b+1); addVect<1>(a+2, b+2, c+2); *(c+2) = *(a+2) + *(b+2); addVect<0>(a+3, b+3, c+3);

Page 40: Metaprogramming

40

Dot Product

template <int DIM, typename T> struct DotProduct {

static T result (T* a, T* b){ return *a * *b +

DotProduct<DIM-1,T>::result(a+1,b+1); }

};

template <typename T> struct DotProduct<1,T> {

static T result (T* a, T* b) { return *a * *b;

} };

Page 41: Metaprogramming

41

Dot Product template <int DIM, typename T> inline T dot_product (T* a, T* b) {

return DotProduct<DIM,T>::result(a,b); }

// usage: int main() {

int a[3] = { 1, 2, 3}; int b[3] = { 5, 6, 7}; std::cout << "dot_product(3,a,b) = "

<< dot_product(3,a,b) << '\n'; std::cout << "dot_product(3,a,a) = " << dot_product(3,a,a);

}

Page 42: Metaprogramming

42

For Loop Unrolling

template<int n, class B>struct FOR {

static void loop(int m) {for (int i = 0; i < m/n; i++) {

UNROLL<n, B>::iteration(i * n);}for (int i = 0; i < m%n; i++) {

B::body(n * m/n + i);}

};

Page 43: Metaprogramming

43

Loop Unrolling …

template <int n, class B>struct UNROLL {

static void iteration(int i) {B::body(i);UNROLL<n-1, B>::iteration(i + 1);

}};template <class B>struct UNROLL<0, B> {

static void iteration(int i) { }};

Page 44: Metaprogramming

44

Meta-programmingLibraries

Page 45: Metaprogramming

45

Loki

By Andrei Alexaderescu “Modern C++ Design” book Covers in DetailImportant components: Small object allocator Typetraits and Typelists Implementing Singletons Smart Pointers Object Factories Visitor

Page 46: Metaprogramming

46

Boost

Major and wildly growing libraryCompatible with STL Important components: Regex Threads Typetraits Lambda Binder Function Object Wrapper FC++ (Functional C++) …

Page 47: Metaprogramming

47

Future of Meta-programming

Page 48: Metaprogramming

48

Future Looks Rosy

Templates as a means for reusable and adaptive software Generic programming poised to become dominant paradigm in C++

Metaprogramming libraries Started - to be used widely 10 Boost libraries – candidates for becoming part

standard More and more programmers are attracted towards

Functional programming in C++ From structured => object-oriented => generic =>

functional ! Don’t faint ;-)

Page 49: Metaprogramming

49

But it won’t be easy

Using templates have their own problems Generic programming is inherently difficult in

nature Using templates needs expertise in C++ Cryptic error messages Readability gets affected, negatively

Metaprograms doesn’t look like C++ code! Too soon to tell how industry will receive it


Recommended