• Non ci sono risultati.

Design Patterns in C++ Metaprogramming applied Giuseppe Lipari

N/A
N/A
Protected

Academic year: 2021

Condividi "Design Patterns in C++ Metaprogramming applied Giuseppe Lipari"

Copied!
17
0
0

Testo completo

(1)

Design Patterns in C++

Metaprogramming applied

Giuseppe Lipari

http://retis.sssup.it/~lipari

Scuola Superiore Sant’Anna – Pisa

April 13, 2011

(2)

Outline

1 Generating classes

2 Linear Hierarchy

3 Generalized Functors

G. Lipari (Scuola Superiore Sant’Anna) Metaprogramming applied April 13, 2011 2 / 17

(3)

How to generate a class with typelists

Suppose you want to generate a class with N fields, of different types

This can be done by using template template parameters, and the typelist facility

template<class TList, template <class> class Unit>

class GenScatterHierarchy;

// empty specialization for NullType (end of list) template<template <class> class Unit>

class GenScatterHierarchy<NullType, Unit> {};

// if an atomic type (not a list), pass it to Unit template <class AtomicType, template <class> class Unit>

class GenScatterHierarchy : public Unit<AtomicType>

{

typedef typename Unit<AtomicType> LeftBase;

};

(4)

GenScatterHierarchy continued

// recursively apply Unit to the TList elements

template <class Head, class Tail, template <class> class Unit>

class GenScatterHierarchy<TypeList<Head, Tail>, Unit> : public GenScatterHierarchy<Head, Unit>,

public GenScatterHierarchy<Tail, Unit>

{

public:

typedef typename TypeList<Head, Tail> TList;

typedef typename GenScatterHierarchy<Head, Unit> LeftBase;

typedef typename GenScatterHierarchy<Tail, Unit> RightBase;

};

GenScatterHierarchyderives from two classes:

the left base applies an atomic type (Head) toUnit the right base is a GenScatterHierarchy applied on the Tail

G. Lipari (Scuola Superiore Sant’Anna) Metaprogramming applied April 13, 2011 4 / 17

(5)

GenScatterHierarchy at work

The best way to understand what is going on, is to do an example with two types,intandstring

first, lets define a template class that will work as anUnit

template <class T>

struct Holder { T value;

};

And now let’s apply it to GenScatterHierarchy:

typedef GenScatterHierarchy<TYPELIST_2(int, string), Holder> MyClass;

That’s it!

What did we obtain?

(6)

The hierarchy

G. Lipari (Scuola Superiore Sant’Anna) Metaprogramming applied April 13, 2011 6 / 17

(7)

Outline

1 Generating classes

2 Linear Hierarchy

3 Generalized Functors

(8)

Linear

Sometimes it is useful to have a linear inheritance hierarchy this can be done if we provide a Holder class with two template parameters

template<class TList,

template<class Atomic, class Base> class Unit, class Root = EmptyType>

class GenLinearHierarchy;

// atomic type

template <class Atomic,

template <class, class> class Unit, class Root>

class GenLinearHierarchy<TYPELIST_1(T), Unit, Root> : public Unit<T, Root> {};

// recursion

template <class Head, class Tail, template <class, class> class Unit, class Root>

class GenLinearHierarchy<TypeList<Head, Tail>, Unit, Root> : public Unit<Head, GenLinearHierarchy<Tail, Unit, Root> > {};

G. Lipari (Scuola Superiore Sant’Anna) Metaprogramming applied April 13, 2011 8 / 17

(9)

A linear hierarchy

template <class T, class Base>

class Handler : public Base { public:

virtual void onEvent(T& obj);

};

typedef GenLinearHierarchy

<

TYPELIST_3(Win, Button, Scroll), Handler

>

EventHandler;

(10)

Outline

1 Generating classes

2 Linear Hierarchy

3 Generalized Functors

G. Lipari (Scuola Superiore Sant’Anna) Metaprogramming applied April 13, 2011 10 / 17

(11)

Functors

Functors in C++ are simple classes that implement the Command pattern

they encapsulate a function call, with its state they allow to defer call to a later times

they allow “call backs”, very useful for building libraries and frameworks

a functor in C++

class Functor { ...

public:

ReturnType operator()(ParameterType p);

};

...

Functor f;

...

f(p1); // call to operator()

(12)

Generalized Functors

we want to design a generalized functor that forwards the call to another function

It can forward to a simple C-like function

it can forward to a member functions of some class it can forward to another functor (to allow chaining) of course, we will use templates a lot

G. Lipari (Scuola Superiore Sant’Anna) Metaprogramming applied April 13, 2011 12 / 17

(13)

Functor basics

Let’s start easy (no parameters)

template<class ReturnType>

class Functor { public:

ResultType operator()();

private:

// implementation };

Now, we want to add parameters to the function call, to allow calling any function, with any number of parameters

of course, parameters can be of different types we need typelists here

(14)

Implementation

Unfortunately, typelists cannot do the magic by themselves, we need to make some repetition.

to simplify things, we are going to build an implementation class FunctorImpl, using the pimpl idiom

template <typename R, class TList>

class FunctorImpl;

template <typename R>

class FunctorImpl<R, NullType> { public:

virtual R operator()() = 0;

virtual FunctorImpl *clone() const = 0;

virtual ~FunctorImpl() {}

};

template <typename R, typename P1>

class FunctorImpl<R, TYPELIST_1(P1)> { public:

virtual R operator()(P1 p1) = 0;

virtual FunctorImpl *clone() const = 0;

virtual ~FunctorImpl() {}

};

...

G. Lipari (Scuola Superiore Sant’Anna) Metaprogramming applied April 13, 2011 14 / 17

(15)

Functor

template<typename R, class TList>

class Functor {

typedef TList ParmList;

typedef typename TypeAtNonStrict<TList, 0, EmptyType>::Result Parm1;

typedef typename TypeAtNonStrict<TList, 1, EmptyType>::Result Parm2;

...

R operator()() { return (*spImpl)(); }

R operator()(Parm1 p1) { return (*spImpl)(p1); }

R operator()(Parm1 p1, Parm2 p2) { return (*spImpl)(p1, p2); } ...

};

Keep in mind that only the correct operator() will be compiled, the other ones will be ignored by the compiler

also, if you try to invoke the wrong operator, you get an error (see code)

(16)

Construction

How to construct functors

template <typename R, class TList>

class Functor { ...

public:

template <typename Fun>

Functor(const Fun& f);

};

Where is the implementation?

We can define FunctorHandler to derive from FunctorImpl, implementing a simple forwarding to f

G. Lipari (Scuola Superiore Sant’Anna) Metaprogramming applied April 13, 2011 16 / 17

(17)

Handlers

template <class ParentFunctor, typename Fun>

class FunctorHandler : public FunctorImpl<

typename ParentFunctor::ResultType, typename ParentFunctor::ParmList> { public:

typedef typename ParentFunctor::ResultType ResultType;

FunctorHandler(const Fun& fun) : fun_(fun) {}

FunctorHandler * clone() const { return new FunctorHandler(*this);

}

ResultType operator()() { return fun_(); }

ResultType operator()(typename ParentFunctor::Parm1 p1) { return fun_(p1);

} ...

private : Fun fun_;

};

Riferimenti

Documenti correlati

õôõôõôõôõô õôõô õô õô

&lt;85&gt; 26-27 dagli elementi in nostro possesso risulta probabile che il copista di L abbia voluto inserire, in maniera indipendente, questa glossa in quanto

17 563 ./0123453.67893:2;??89@A=B3C83:DEFG.3/=@3F=@2113L/CA2=C;3MN3O3PQR STTUTTVUWXYZ[Y\UT]ZWTUY^YWZ_Y`ab cZV]dUXUY\UT]ZWTUY e fg\XhgdY\UT]ZWTUY ijY`ikb lXgmdUYnhTUgTUY

[r]

Testing is done while coding, while debugging is done later, Testing is a special kind of coding, while debugging means slowly going through existing code in a painful way and

In De l’esprit des lois Montesquieu shows that a multitude of variables in a society, including the laws, commerce, and religion, interact with one another to

[r]

FRAGILI E + LEGATE AL MODO TRADIZIONALE DI FARE LA GUERRA (...)  SOPRATTUTTO MILITARI, DALL’ALTRO MOLTIPLICA LE RAGIONI DELLA SCELTA PARTIGIANA.. - ULTERIORE SPINTA ASSAI