• Keine Ergebnisse gefunden

Object-Oriented Programming for Scientific Computing

N/A
N/A
Protected

Academic year: 2021

Aktie "Object-Oriented Programming for Scientific Computing"

Copied!
51
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Object-Oriented Programming for Scientific Computing

Template Metaprogramming

Ole Klein

Interdisciplinary Center for Scientific Computing Heidelberg University

ole.klein@iwr.uni-heidelberg.de

30. Juni 2015

(2)

Calculating the Square Root

We can calculate the square root as follows using nested intervals:

# include< i o s t r e a m >

t e m p l a t e< std :: s i z e _ t N , std :: s i z e _ t L =1 , std :: s i z e _ t H = N >

s t r u c t S q r t {

p u b l i c:

e n u m{ mid = ( L + H +1) /2 };

e n u m{ v a l u e = ( N < mid * mid ) ? ( std :: s i z e _ t ) Sqrt < N , L , mid -1 >:: v a l u e : ( std :: s i z e _ t ) Sqrt < N , mid , H >:: v a l u e };

};

t e m p l a t e< std :: s i z e _ t N , std :: s i z e _ t M >

s t r u c t Sqrt < N , M , M >

{

e n u m{ v a l u e = M };

};

int m a i n () {

std :: cout < < Sqrt <9 >:: value < <" "< < Sqrt <42 >:: value < < std :: e n d l ; }

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 2 / 51

(3)

Template Instantiations

Calculating

Sqrt<9>

first leads to the execution of:

Sqrt <9 ,1 ,9 >:: v a l u e = (9 <25) ? Sqrt <9 ,1 ,4 >:: v a l u e : Sqrt <9 ,5 ,9 >:: v a l u e = Sqrt <9 ,1 ,4 >:: v a l u e

As a result

Sqrt<9,1,4>

is calculated next:

Sqrt <9 ,1 ,4 >:: v a l u e = (9 <9) ? Sqrt <9 ,1 ,2 >:: v a l u e : Sqrt <9 ,3 ,4 >:: v a l u e = Sqrt <9 ,3 ,4 >:: v a l u e

The next recursion step is then:

Sqrt <9 ,3 ,4 >:: v a l u e = (9 <16) ? Sqrt <9 ,3 ,3 >:: v a l u e : Sqrt <9 ,4 ,3 >:: v a l u e = Sqrt <9 ,3 ,3 >:: v a l u e = 3

However, there is a problem with the ternary operator

<condition>?<true-path>:<false-path>

. The compiler generates not just the

relevant part, but also the other that is not used. This means it has to

expand the next recursion level on that side as well (although the result will

(4)

Type Selection at Compile Time

We can get rid of the unnecessary template instantiations by simply selecting the correct type and evaluating it directly.

This can be carried out with a small metaprogram that corresponds to an

if

statement (also called a “compile time type selection”).

// D e f i n i t i o n i n c l u d i n g s p e c i a l i z a t i o n f o r t h e t r u e c a s e t e m p l a t e<b o o l B , t y p e n a m e T1 , t y p e n a m e T2>

s t r u c t I f T h e n E l s e {

t y p e d e f T1 R e s u l t T ; };

// P a r t i a l s p e c i a l i z a t i o n f o r t h e f a l s e c a s e t e m p l a t e<t y p e n a m e T1 , t y p e n a m e T2>

s t r u c t I f T h e n E l s e<f a l s e , T1 , T2>

{

t y p e d e f T2 R e s u l t T ; };

#e n d i f

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 4 / 51

(5)

Improved Calculation of the Square Root

Using our meta-

if

statement we can implement the square root as follows:

t e m p l a t e<s t d : : s i z e t N , s t d : : s i z e t L=1 , s t d : : s i z e t H=N>

s t r u c t S q r t {

p u b l i c:

enum{ mid = ( L+H+1) /2 };

t y p e d e f t y p e n a m e I f T h e n E l s e<(N<mid∗mid ) , S q r t<N , L , mid−1>,

S q r t<N , mid , H> >: : R e s u l t T R e s u l t T y p e ;

enum{ v a l u e = R e s u l t T y p e : : v a l u e }; };

t e m p l a t e<s t d : : s i z e t N , s t d : : s i z e t M>

s t r u c t S q r t<N ,M,M>

{

enum{ v a l u e = M };

(6)

Turing Completeness of Template Metaprogramming

Template meta programs may include:

State variables: the template parameters.

Loops: using recursion.

Conditional execution: using the ternary operator or template specialization (e.g. the meta-

if

).

Integer calculations.

This is sufficient to perform any calculation, as long as there isn’t any restriction on the number of recursive instantiations and on the number of state variables (which does not imply that it is useful to calculate everything with template metaprogramming) .

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 6 / 51

(7)

Loop Unrolling

In the calculation of a scalar product, as in:

t e m p l a t e<t y p e n a m e T >

i n l i n e T d o t _ p r o d u c t (int dim , T * a , T * b ) {

T r e s u l t = T () ;

for (int i =0; i < dim ;++ i ) {

r e s u l t += a [ i ]* b [ i ];

}

r e t u r n r e s u l t ; }

the compiler often optimizes the computation for large arrays. However, if small scalar products of the type

dp = d o t _ p r o d u c t (3 , a , b ) ;

(8)

Loop Unrolling

// P r i m a r y t e m p l a t e

t e m p l a t e <int DIM , t y p e n a m e T >

c l a s s D o t P r o d u c t {

p u b l i c:

s t a t i c T r e s u l t ( T * a , T * b ) {

r e t u r n * a * * b + D o t P r o d u c t < DIM -1 , T >:: r e s u l t ( a +1 , b +1) ; }

};

// P a r t i a l s p e c i a l i z a t i o n as s t o p p i n g c r i t e r i o n t e m p l a t e <t y p e n a m e T >

c l a s s D o t P r o d u c t <1 , T >

{

p u b l i c:

s t a t i c T r e s u l t ( T * a , T * b ) {

r e t u r n * a * * b ; }

};

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 8 / 51

(9)

Loop Unrolling

// for s i m p l i f i c a t i o n

t e m p l a t e <int DIM , t y p e n a m e T >

i n l i n e T d o t _ p r o d u c t ( T * a , T * b ) {

r e t u r n D o t P r o d u c t < DIM , T >:: r e s u l t ( a , b ) ; }

(10)

Application: Loop Unrolling

# i n c l u d e < i o s t r e a m >

# i n c l u d e " l o o p _ u n r o l l i n g . h "

int m a i n () {

int a [3] = { 1 , 2 , 3};

int b [3] = { 5 , 6 , 7};

std :: c o u t < < " d o t _ p r o d u c t <3 >( a , b ) = "

< < d o t _ p r o d u c t <3 >( a , b ) < < ’ \ n ’;

std :: c o u t < < " d o t _ p r o d u c t <3 >( a , a ) = "

< < d o t _ p r o d u c t <3 >( a , a ) < < ’ \ n ’;

}

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 10 / 51

(11)

Loop Unrolling for Random Access Container

// P r i m a r y t e m p l a t e

t e m p l a t e <int DIM , t y p e n a m e T , t e m p l a t e<t y p e n a m e U ,t y p e n a m e= std :: a l l o c a t o r < U > > c l a s s vect >

s t r u c t D o t P r o d u c t {

s t a t i c T r e s u l t (c o n s t vect < T > & a , c o n s t vect < T > & b ) {

r e t u r n a [ DIM - 1 ] * b [ DIM -1] +

D o t P r o d u c t < DIM -1 , T , vect >:: r e s u l t ( a , b ) ; }

};

// P a r t i a l s p e c i a l i z a t i o n as s t o p p i n g c r i t e r i o n t e m p l a t e <t y p e n a m e T , t e m p l a t e<t y p e n a m e

U ,t y p e n a m e= std :: a l l o c a t o r < U > > c l a s s vect >

s t r u c t D o t P r o d u c t <1 , T , vect >

{

s t a t i c T r e s u l t (c o n s t vect < T > & a , c o n s t vect < T > & b )

(12)

Loop Unrolling for Random Access Container

// For s i m p l i f i c a t i o n

t e m p l a t e <int DIM , t y p e n a m e T , t e m p l a t e<t y p e n a m e U ,t y p e n a m e= std :: a l l o c a t o r < U > > c l a s s vect >

i n l i n e T d o t _ p r o d u c t (c o n s t vect < T > & a , c o n s t vect < T > & b ) {

r e t u r n D o t P r o d u c t < DIM , T , vect >:: r e s u l t ( a , b ) ; }

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 12 / 51

(13)

Application: Loop Unrolling for Random Access Container

# i n c l u d e < i o s t r e a m >

# i n c l u d e < vector >

# i n c l u d e " l o o p _ u n r o l l i n g 2 . h "

int m a i n () {

std :: vector <double> a (3 ,3.0) ; std :: vector <double> b (3 ,5.0) ;

std :: c o u t < < " d o t _ p r o d u c t <3 >( a , b ) = "

< < d o t _ p r o d u c t <3 >( a , b ) < < ’ \ n ’;

std :: c o u t < < " d o t _ p r o d u c t <3 >( a , a ) = "

< < d o t _ p r o d u c t <3 >( a , a ) < < ’ \ n ’;

}

(14)

constexpr

# include< i o s t r e a m >

int x1 = 7;

c o n s t e x p r int x2 = 7;

c o n s t e x p r int x3 = x1 ; // Error , x1 is not a c o n s t e x p r c o n s t e x p r int x4 = x2 ;

c o n s t e x p r int Fac (int n ) {

r e t u r n n <2 ? 1 : n * Fac ( n -1) ; }

int m a i n () {

std :: c o u t < < Fac ( 1 0 ) < < std :: e n d l ; }

C++11 introduces a simple alternative to template metaprogramming:

expressions that are already evaluated at compile time.

In a

constexpr

only variables or functions which are

constexpr

themselves may be used.

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 14 / 51

(15)

constexpr

It must be possible to evaluate a

constexpr

at compile time:

v o i d f (int n ) {

c o n s t e x p r int x = Fac ( n ) ; // Error , n isn ’ t k n o w n at // t i m e of t r a n s l a t i o n

int f10 = Fac ( 1 0 ) ; // C o r r e c t

}

int m a i n () {

c o n s t int ten = 10;

int f10 = Fac ( 1 0 ) ; // A l s o c o r r e c t

}

(16)

constexpr

This will work even for objects of classes whose constructor is simple enough to be defined as

constexpr

:

s t r u c t P o i n t {

int x , y ;

c o n s t e x p r P o i n t (int xx , int yy ) : x ( xx ) , y ( yy ) {}

};

c o n s t e x p r P o i n t o r i g o (0 ,0) ; c o n s t e x p r int z = o r i g o . x ;

c o n s t e x p r P o i n t a [] = { P o i n t (0 ,0) , P o i n t (1 ,1) , P o i n t (2 ,2) };

c o n s t e x p r x = a [ 1 ] . x ; // x b e c o m e s 1

• constexpr

functions may not have the return type

void

and neither variables nor functions may be defined within them (this also applies to

constexpr

constructors).

The function body can only contain declarations and a single

return

statement.

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 16 / 51

(17)

Example: Numbers with Units

Template Metaprogramming Example: Numbers with Units

When performing calculations with physical quantities errors may occur.

The worst case scenario is comparing apples and oranges.

The aim is the construction of a class which allows calculating with units.

The implementation uses template metaprogramming. All calculations (except the conversion for input and output) are as fast as without units.

The necessary tests are performed at compile time and automatically

optimized out.

(18)

Example: Numbers with Units

Units: Unit Class

We first introduce a template class for units:

t e m p l a t e<int M , int K , int S >

s t r u c t U n i t {

e n u m { m = M , kg = K , s = S };

};

u s i n g M = Unit <1 ,0 ,0 >; // M e t e r s u s i n g Kg = Unit <0 ,1 ,0 >; // K i l o g r a m u s i n g S = Unit <0 ,0 ,1 >; // S e c o n d s

u s i n g MpS = Unit <1 ,0 , -1 >; // M e t e r per s e c o n d ( m / s )

u s i n g M p S 2 = Unit <1 ,0 , -2 >; // M e t e r per s e c o n d s q u a r e d ( m /( s * s ) )

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 18 / 51

(19)

Example: Numbers with Units

Enum Classes

e n u m { RED , GREEN , B L U E }; // C e n u m

e n u m c l a s s C o l o r { RED , GREEN , B L U E }; // C + + 1 1 e n u m

In C enums are simply integer values with a name.

The same name may be used only once.

Such an enum can be used in exactly the same places where any other integer value can be used.

C++11 introduces enum classes, so that each enum class is its own type and has its own name and thus namespace. This way both problems described above are solved.

Such enums can only be cast to integer explicitly, and therefore C enums

remain useful for template metaprogramming.

(20)

Example: Numbers with Units

Enum Classes

# include< i o s t r e a m >

e n u m c l a s s T i m e I n t e g r a t i o n : u n s i g n e d c h a r { EE = 2 , IE = 4 , CN = 8 , B D F 2 = 1 6 } ;

// u s e s int as i n t e r n a l d a t a t y p e

e n u m c l a s s S p a t i a l I n t e g r a t i o n { CCFV , FCFV , FE , DG };

t e m p l a t e< T i m e I n t e g r a t i o n T , S p a t i a l I n t e g r a t i o n S >

v o i d D o T i m e S t e p () {

// e x p l i c i t c o n v e r s i o n to int p o s s i b l e

std :: c o u t < < (u n s i g n e d int) T < < " " < < (int) S < < std :: e n d l ; }

int m a i n () {

// s c o p e has to be i n c l u d e d

D o T i m e S t e p < T i m e I n t e g r a t i o n :: CN , S p a t i a l I n t e g r a t i o n :: FE >() ; T i m e I n t e g r a t i o n ti = T i m e I n t e g r a t i o n :: IE ;

ti = 1; // not p o s s i b l e , no i m p l i c i t c o n v e r s i o n

S p a t i a l I n t e g r a t i o n si = ti ; // not p o s s i b l e , w r o n g t y p e }

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 20 / 51

(21)

Example: Numbers with Units

Units: Helper Classes

In order to calculate with units, we require some helper classes. We build template functions with

using

declarations.

t e m p l a t e<t y p e n a m e U1 , t y p e n a m e U2 >

s t r u c t U p l u s {

u s i n g t y p e = Unit < U1 :: m + U2 :: m , U1 :: kg + U2 :: kg , U1 :: s + U2 :: s >;

};

t e m p l a t e<t y p e n a m e U1 , t y p e n a m e U2 >

u s i n g U n i t _ p l u s = t y p e n a m e Uplus < U1 , U2 >:: t y p e ; t e m p l a t e<t y p e n a m e U1 , t y p e n a m e U2 >

s t r u c t U m i n u s {

u s i n g t y p e = Unit < U1 :: m - U2 :: m , U1 :: kg - U2 :: kg , U1 :: s - U2 :: s >;

};

t e m p l a t e<t y p e n a m e U1 , t y p e n a m e U2 >

u s i n g U n i t _ m i n u s = t y p e n a m e Uminus < U1 , U2 >:: t y p e ;

(22)

Example: Numbers with Units

Quantities

Now we can introduce a class in which the values are stored together with their units. Since the units are only used as a template parameter, this only affects the class type but does not require memory. In order to remain as flexible as possible, the data type is also a template parameter.

t e m p l a t e<t y p e n a m e U , t y p e n a m e V =double>

s t r u c t Q u a n t i t y { V val ;

e x p l i c i t c o n s t e x p r Q u a n t i t y ( V d ) : val { d } {}

t e m p l a t e<t y p e n a m e V2 >

c o n s t e x p r Q u a n t i t y ( Q u a n t i t y < U , V2 > d ) : val {s t a t i c _ c a s t< V >( d . val ) } {}

};

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 22 / 51

(23)

Example: Numbers with Units

Explicit Conversion

Constructors with one argument are used by C++ for automatic type conversion.

This isn’t always desired. In this example it shouldn’t be possible to add or subtract a number without unit to/from one with unit.

In C++11, constructors can be made

explicit

.

In this case the constructor will only be used when it is explicitly called, for

example with

Quantity<M>(2.73)

.

(24)

Example: Numbers with Units

Quantities: Addition and Subtraction

We can now calculate with quantities. For addition and subtraction, the unit of the two operands and the result have to be the same. All data types which have an appropriate

operator+

or

operator-

can be used.

t e m p l a t e<t y p e n a m e U , t y p e n a m e V1 , t y p e n a m e V2 >

a u t o o p e r a t o r+( Q u a n t i t y < U , V1 > x , Q u a n t i t y < U , V2 >

y ) - > Q u a n t i t y < U , d e c l t y p e ( x . val + y . val ) >

{

r e t u r n Q u a n t i t y < U , d e c l t y p e ( x . val + y . val ) >( x . val + y . val ) ; }

t e m p l a t e<t y p e n a m e U , t y p e n a m e V1 , t y p e n a m e V2 >

a u t o o p e r a t o r-( Q u a n t i t y < U , V1 > x , Q u a n t i t y < U , V2 >

y ) - > Q u a n t i t y < U , d e c l t y p e ( x . val - y . val ) >

{

r e t u r n Q u a n t i t y < U , d e c l t y p e ( x . val - y . val ) >( x . val - y . val ) ; }

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 24 / 51

(25)

Example: Numbers with Units

Quantities: Multiplication and Division

During multiplication the units are added componentwise, while for division they are subtracted.

t e m p l a t e<t y p e n a m e U1 , t y p e n a m e U2 , t y p e n a m e V1 , t y p e n a m e V2 >

a u t o o p e r a t o r*( Q u a n t i t y < U1 , V1 > x , Q u a n t i t y < U2 , V2 >

y ) - > Q u a n t i t y < U n i t _ p l u s < U1 , U2 > , d e c l t y p e ( x . val * y . val ) >

{

r e t u r n

Q u a n t i t y < U n i t _ p l u s < U1 , U2 > , d e c l t y p e ( x . val * y . val ) >( x . val * y . val ) ; }

t e m p l a t e<t y p e n a m e U1 , t y p e n a m e U2 , t y p e n a m e V1 , t y p e n a m e V2 >

a u t o o p e r a t o r/( Q u a n t i t y < U1 , V1 > x , Q u a n t i t y < U2 , V2 >

y ) - > Q u a n t i t y < U n i t _ m i n u s < U1 , U2 > , d e c l t y p e ( x . val / y . val ) >

{

r e t u r n

(26)

Example: Numbers with Units

Quantities: Multiplication by Values without Unit

The unit remains the same when a quantity is multiplied by a value without unit.

t e m p l a t e<t y p e n a m e U ,t y p e n a m e V1 , t y p e n a m e V2 >

a u t o o p e r a t o r*( Q u a n t i t y < U , V1 > x , V2 y ) - > Q u a n t i t y < U , d e c l t y p e ( x . val * y ) >

{

r e t u r n Q u a n t i t y < U , d e c l t y p e ( x . val * y ) >( x . val * y ) ; }

t e m p l a t e<t y p e n a m e U ,t y p e n a m e V1 , t y p e n a m e V2 >

a u t o o p e r a t o r*( V1 y , Q u a n t i t y < U , V2 >

x ) - > Q u a n t i t y < U , d e c l t y p e ( x . val * y ) >

{

r e t u r n Q u a n t i t y < U , d e c l t y p e ( x . val * y ) >( x . val * y ) ; }

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 26 / 51

(27)

Example: Numbers with Units

Quantities: Division using Values without Unit

If a quantity is divided by a number without unit the same as for multiplication holds. If the quantity is the divisor, the signs of the components of the unit have to be switched.

t e m p l a t e<t y p e n a m e U ,t y p e n a m e V1 , t y p e n a m e V2 >

a u t o o p e r a t o r/( Q u a n t i t y < U , V1 > x , V2 y ) - > Q u a n t i t y < U , d e c l t y p e ( x . val / y ) >

{

r e t u r n Q u a n t i t y < U , d e c l t y p e ( x . val / y ) >( x . val / y ) ; }

t e m p l a t e<t y p e n a m e U ,t y p e n a m e V1 , t y p e n a m e V2 >

a u t o o p e r a t o r/( V1 y , Q u a n t i t y < U , V2 >

x ) - > Q u a n t i t y < U n i t _ n e g a t e < U > , d e c l t y p e ( y / x . val ) >

{

r e t u r n Q u a n t i t y < U n i t _ n e g a t e < U > , d e c l t y p e ( y / x . val ) >( y / x . val ) ;

(28)

Example: Numbers with Units

Custom Literals

It would be nice if it was possible to define more literals in addition to the builtin ones, e.g.

" Hi ! "s // string , not ‘ ‘ zero - t e r m i n a t e d a r r a y of c h a r ’ ’

1.2 i // i m a g i n a r y n u m b e r

1 2 3 . 4 5 6 7 8 9 1 2 3 4 df // d e c i m a l f l o a t i n g p o i n t ( IBM ) 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 b // b i n a r y n u m b e r

123 s // s e c o n d s

1 2 3 . 5 6 km // k i l o m e t e r s

1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 x // e x t e n d e d - p r e c i s i o n

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 28 / 51

(29)

Example: Numbers with Units

Custom Literals

This is possible in C++11, e.g. for complex numbers and strings (their suffix has to start with a

’_’

, however):

c o n s t e x p r complex <double> o p e r a t o r" " _i (l o n g d o u b l e d ) //

i m a g i n a r y l i t e r a l {

r e t u r n {0 , d }; // r e t u r n s the a p p r o p r i a t e c o m p l e x n u m b e r }

std :: s t r i n g o p e r a t o r" " _s (c o n s t c h a r* p , s i z e _ t n ) //

std :: s t r i n g l i t e r a l {

r e t u r n s t r i n g ( p , n ) ; }

This can be used as follows:

t e m p l a t e<c l a s s T > v o i d f (c o n s t T &) ;

f (" H e l l o ") ; // h a n d s c o n s t c h a r * to f u n c t i o n

(30)

Example: Numbers with Units

Custom Literals

C strings may also be passed directly:

B i g n u m o p e r a t o r" " _x (c o n s t c h a r* p ) {

r e t u r n B i g n u m ( p ) ; }

v o i d f ( B i g n u m ) ;

f ( 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 _x ) ;

but not always:

std :: s t r i n g o p e r a t o r" " _S (c o n s t c h a r* p ) ; // t h i s d o e s n ’ t w o r k std :: s t r i n g b l u b = " one two "_S ; // E r r o r : no a p p l i c a b l e l i t e r a l

o p e r a t o r

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 30 / 51

(31)

Example: Numbers with Units

Raw String Literals

If one wants to use a backslash in a string, then it has to be written as

\\

. This makes the string difficult to read, especially in the newly introduced regular expressions:

s t r i n g s = " \\ w \ \ \ \ \ \ w "; // H o p e f u l l y g e t t i n g t h i s e x a m p l e r i g h t ...

In a raw string literal, each character is simply written directly as such:

std :: s t r i n g s = R" (\ w \\\ w ) "; // I ’ m p r e t t y s u r e I got t h a t r i g h t std :: s t r i n g p a t h = R" ( c :\ P r o g r a m m e \ b l u b \ b l o b . exe ) ";

The first proposal for the introduction of raw string literals has been motivated by the following example:

" ( ’ ( ? : [ ^ \ \ \ \ ’ ] | \ \ \ \ . ) * ’ | \ " ( ? : [ ^ \ \ \ \ \ " ] | \ \ \ \ . ) * \ " ) | "

// Are the f i v e b a c k s l a s h e s c o r r e c t or not ?

(32)

Example: Numbers with Units

Raw String Literals

A raw string literal starts with

R"(

and ends with

)"

.

R" ( "q u o t e d s t r i n g" ) " // the s t r i n g is " q u o t e d s t r i n g "

Should it happen that the combination

"(

or

)"

occurs in the string, then an arbitrary combination of characters can be inserted between the parenthesis and the quotation marks to make the delimiter unique:

R" * * * ( "q u o t e d s t r i n g c o n t a i n i n g the u s u a l t e r m i n a t o r (" ]) ") ***"

// the s t r i n g is "q u o t e d s t r i n g c o n t a i n i n g the u s u a l t e r m i n a t o r (" ]) "

Short version of the above regular expression:

" ’ ( [ ^ \ \ \ \ ’ ] | \ \ \ \ . ) * ’ | \ " ( [ ^ \ \ \ \ \ " ] | \ \ \ \ . ) *\" "

Equivalent raw string literal:

R" ( ’ ( [ ^ \ \ ’ ] | \ \ . ) * ’ | \ " ( [ ^ \ \ \ " ] | \ \ . ) * \ " ) "

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 32 / 51

(33)

Example: Numbers with Units

Regular Expressions

As in many other programming languages, regular expressions can also be used in C++11:

# include< regex >

# include< i o s t r e a m >

# include< string >

int m a i n () {

std :: r e g e x n a m e _ r e ( R" - -(([ a - zA - Z ]+) \ s +([ a - zA - Z ]+) ) - - ") ; std :: s t r i n g n a m e =" T o r s t e n W i l l ";

if( r e g e x _ m a t c h ( n a m e . b e g i n () , n a m e . end () , n a m e _ r e ) ) std :: c o u t < < " H e l l o " < < n a m e < < std :: e n d l ; e l s e

std :: c o u t < < " Who are you ? " < < std :: e n d l ; }

(34)

Example: Numbers with Units

String to Number and Number to String Conversion

# include< string >

# i n c l u d e" p r i n t . h "

int m a i n () {

std :: s t r i n g s V a l = " -2.47 3 . 1 4 1 5 1 e 3 0 0 42 3 7 6 8 5 7 6 8 9 4 0 3 0 xFF ";

s i z e _ t n e x t =0;

f l o a t f V a l = std :: s t o f ( sVal ,& n e x t ) ; s V a l = s V a l . s u b s t r ( n e x t ) ;

d o u b l e d V a l = std :: s t o d ( sVal ,& n e x t ) ; s V a l = s V a l . s u b s t r ( n e x t ) ;

l o n g d o u b l e l d V a l = std :: s t o l d ( sVal ,& n e x t ) ; s V a l = s V a l . s u b s t r ( n e x t ) ;

int i V a l = std :: s t o i ( sVal ,& n e x t ) ; s V a l = s V a l . s u b s t r ( n e x t ) ;

l o n g l V a l = std :: s t o l ( sVal ,& n e x t ) ; s V a l = s V a l . s u b s t r ( n e x t ) ;

u n s i g n e d l o n g u l V a l = std :: s t o u l ( sVal ,& next , 1 6 ) ; P r i n t f (" % d , % d , % d , % s , % g , % s \ n ", iVal , lVal , ulVal ,

std :: t o _ s t r i n g ( f V a l ) , dVal , std :: t o _ s t r i n g ( l d V a l ) ) ; }

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 34 / 51

(35)

Example: Numbers with Units

Literals for Quantities with Floating Point Numbers

Now we can define a large amount of personal literals. First for quantities which are using floating point numbers as data type:

c o n s t e x p r Q u a n t i t y < M ,l o n g double> o p e r a t o r" " _m (l o n g d o u b l e v a l u e ) {

r e t u r n Q u a n t i t y < M ,l o n g double> { v a l u e };

}

c o n s t e x p r Q u a n t i t y < Kg ,l o n g double> o p e r a t o r" " _kg (l o n g d o u b l e v a l u e )

{

r e t u r n Q u a n t i t y < Kg ,l o n g double> { v a l u e };

}

c o n s t e x p r Q u a n t i t y < S ,l o n g double> o p e r a t o r" " _s (l o n g d o u b l e v a l u e ) {

r e t u r n Q u a n t i t y < S ,l o n g double> { v a l u e };

}

(36)

Example: Numbers with Units

Literals for Quantities with Floating Point Numbers

c o n s t e x p r Q u a n t i t y < Kg ,l o n g double> o p e r a t o r" " _g (l o n g d o u b l e v a l u e ) {

r e t u r n Q u a n t i t y < Kg ,l o n g double> { v a l u e / 1 0 0 0 } ; }

c o n s t e x p r Q u a n t i t y < Kg ,l o n g double> o p e r a t o r" " _mg (l o n g d o u b l e v a l u e )

{

r e t u r n Q u a n t i t y < Kg ,l o n g double> { v a l u e / 1 0 0 0 0 0 0 } ; }

c o n s t e x p r Q u a n t i t y < S ,l o n g double> o p e r a t o r" " _ m i n (l o n g d o u b l e v a l u e )

{

r e t u r n Q u a n t i t y < S ,l o n g double> { 6 0 * v a l u e };

}

c o n s t e x p r Q u a n t i t y < S ,l o n g double> o p e r a t o r" " _h (l o n g d o u b l e v a l u e ) {

r e t u r n Q u a n t i t y < S ,l o n g double> { 3 6 0 0 * v a l u e };

}

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 36 / 51

(37)

Example: Numbers with Units

Literals for Quantities with Floating Point Numbers

c o n s t e x p r Q u a n t i t y < S ,l o n g double> o p e r a t o r" " _d (l o n g d o u b l e v a l u e ) {

r e t u r n Q u a n t i t y < S ,l o n g double> { 8 6 4 0 0 * v a l u e };

}

c o n s t e x p r Q u a n t i t y < S ,l o n g double> o p e r a t o r" " _ms (l o n g d o u b l e v a l u e ) {

r e t u r n Q u a n t i t y < S ,l o n g double> { v a l u e / 1 0 0 0 } ; }

c o n s t e x p r Q u a n t i t y < S ,l o n g double> o p e r a t o r" " _us (l o n g d o u b l e v a l u e ) {

r e t u r n Q u a n t i t y < S ,l o n g double> { v a l u e / 1 0 0 0 0 0 0 } ; }

c o n s t e x p r Q u a n t i t y < S ,l o n g double> o p e r a t o r" " _ns (l o n g d o u b l e v a l u e ) {

(38)

Example: Numbers with Units

Literals for Quantities with Integers

Then also for quantities that use integer data types:

c o n s t e x p r Q u a n t i t y < M ,u n s i g n e d l o n g long> o p e r a t o r" " _m (u n s i g n e d l o n g l o n g v a l u e )

{

r e t u r n Q u a n t i t y < M ,u n s i g n e d l o n g long> { v a l u e };

}

c o n s t e x p r Q u a n t i t y < Kg ,u n s i g n e d l o n g long> o p e r a t o r" " _kg (u n s i g n e d l o n g l o n g v a l u e )

{

r e t u r n Q u a n t i t y < Kg ,u n s i g n e d l o n g long> { v a l u e };

}

c o n s t e x p r Q u a n t i t y < S ,u n s i g n e d l o n g long> o p e r a t o r" " _s (u n s i g n e d l o n g l o n g v a l u e )

{

r e t u r n Q u a n t i t y < S ,u n s i g n e d l o n g long> { v a l u e };

}

And so on, as above for floating point numbers.

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 38 / 51

(39)

Example: Numbers with Units

Quantities: Squaring and Comparison

We also want to be able to square quantities and compare them.

t e m p l a t e<t y p e n a m e U , t y p e n a m e V >

Q u a n t i t y < U n i t _ p l u s < U , U > , V > s q u a r e ( Q u a n t i t y < U , V > x ) {

r e t u r n Q u a n t i t y < U n i t _ p l u s < U , U > , V >( x . val * x . val ) ; }

t e m p l a t e<t y p e n a m e U ,t y p e n a m e V >

b o o l o p e r a t o r==( Q u a n t i t y < U , V > x , Q u a n t i t y < U , V > y ) {

r e t u r n x . val == y . val ; }

t e m p l a t e<t y p e n a m e U ,t y p e n a m e V >

b o o l o p e r a t o r!=( Q u a n t i t y < U , V > x , Q u a n t i t y < U , V > y ) {

(40)

Example: Numbers with Units

Quantities: Larger and Smaller

Checks for inequality should even be possible for different data types when the unit matches:

}

t e m p l a t e<t y p e n a m e U ,t y p e n a m e V1 , t y p e n a m e V2 >

b o o l o p e r a t o r<( Q u a n t i t y < U , V1 > x , Q u a n t i t y < U , V2 > y ) {

r e t u r n x . val < y . val ; }

t e m p l a t e<t y p e n a m e U ,t y p e n a m e V1 , t y p e n a m e V2 >

b o o l o p e r a t o r>( Q u a n t i t y < U , V1 > x , Q u a n t i t y < U , V2 > y ) {

r e t u r n x . val > y . val ; }

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 40 / 51

(41)

Example: Numbers with Units

Quantities: Output

We would like to be able to display quantities with the correct units. This can be achieved with a simple function and an overloaded output operator:

std :: s t r i n g s u f f i x (int u , c o n s t c h a r* x ) {

std :: s t r i n g suf ; if ( u ) {

suf += x ;

if (1 < u ) suf += ’ 0 ’ + u ; if ( u <0) {

suf += ’ - ’;

suf += ’ 0 ’ - u ; }

}

r e t u r n suf ; }

t e m p l a t e<t y p e n a m e U , t y p e n a m e V >

(42)

Example: Numbers with Units

Quantities: Application Example

Now we can calculate with our quantities:

# i n c l u d e" u n i t s . h "

int m a i n () {

Q u a n t i t y < M ,double> x { 1 0 . 5 } ; Q u a n t i t y < S ,int> y { 2 } ;

Q u a n t i t y < MpS ,double> v = x / y ; v = 2* v ;

a u t o d i s t a n c e = 10 _m ;

Q u a n t i t y < S ,double> t i m e = 20 _s ; a u t o s p e e d = d i s t a n c e / t i m e ;

Q u a n t i t y < MpS2 ,double> a c c e l e r a t i o n = d i s t a n c e / s q u a r e ( t i m e ) ; std :: c o u t < < " S p e e d = " < < s p e e d < < " A c c e l e r a t i o n = " < <

a c c e l e r a t i o n < < std :: e n d l ; }

Output:

Velocity = 0.5ms-1 Acceleration = 0.025ms-2

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 42 / 51

(43)

Variadic Templates: C++ Printf

C++ Printf

The function

printf()

has been a simple C function in C++, but in C++11 this isn’t necessarily the case any more. The application looks as follows:

# i n c l u d e" p r i n t . h "

int m a i n () {

c o n s t c h a r * pi = " pi ";

P r i n t f (" The v a l u e of % s is a b o u t % g ( u n l e s s you l i v e in % s ) .\ n ", pi , 3 . 1 4 1 5 9 , " I n d i a n a ") ;

c o n s t std :: s t r i n g n a m e =" S t e f a n ";

int age = 2 4 ; f l o a t g r a d e = 1 . 3 ; P r i n t f (

R" ( The s t u d e n t % s , % d y e a r s old , has r e c e i v e d the g r a d e % g . He is a m o n g the top 1 %%.

) ", name , age , g r a d e ) ; }

(44)

Variadic Templates: C++ Printf

Variadic Templates

The easiest case of

printf()

is the one where no arguments other than the format string exist:

# include< i o s t r e a m >

# include< t y p e _ t r a i t s >

# include< s t d e x c e p t >

v o i d P r i n t f (c o n s t c h a r * s ) {

if ( s == n u l l p t r ) r e t u r n;

w h i l e (* s ) {

if (* s ==’ % ’ && *++ s !=’ % ’) // m a k e s u r e t h a t t h e r e a r e n ’ t any // a r g u m e n t s . %% is a n o r m a l % in a // f o r m a t s t r i n g

t h r o w std :: r u n t i m e _ e r r o r (" i n v a l i d f o r m a t : m i s s i n g a r g u m e n t s ") ;

std :: c o u t < < * s ++;

} }

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 44 / 51

(45)

Variadic Templates: C++ Printf

Variadic Templates

We now have to treat the case of

printf()

with several arguments. This requires a variable number of template arguments:

t e m p l a t e<t y p e n a m e T , t y p e n a m e... Args > // n o t e the " . . . "

v o i d P r i n t f (c o n s t c h a r* s , T value , A r g s ... a r g s ) {

w h i l e ( s && * s ) {

if (* s ==’ % ’) { s w i t c h ( * + + s ) {

c a s e ’ % ’:

b r e a k; c a s e ’ s ’:

if (! I s _ C _ s t y l e _ s t r i n g < T >() && ! I s _ s t r i n g < T >() ) t h r o w std :: r u n t i m e _ e r r o r (" Bad P r i n t f () f o r m a t ") ; b r e a k;

c a s e ’ d ’:

(46)

Variadic Templates: C++ Printf

Variadic Templates

c a s e ’ g ’:

if (! std :: i s _ f l o a t i n g _ p o i n t < T >() )

t h r o w std :: r u n t i m e _ e r r o r (" Bad P r i n t f () f o r m a t ") ; b r e a k;

d e f a u l t:

t h r o w std :: r u n t i m e _ e r r o r (" U n k n o w n P r i n t f () f o r m a t ") ; }

std :: c o u t < < v a l u e ;

r e t u r n( P r i n t f (++ s , a r g s . . . ) ) ; // h e r e a g a i n n o t e the " . . . "

}

std :: c o u t < < * s ++;

}

t h r o w std :: r u n t i m e _ e r r o r (" E x t r a a r g u m e n t s p r o v i d e d to P r i n t f ") ; }

Using variadic templates, only the first element of the argument list is visible in each function call.

T

can be a different type for each call. The remainder may then be passed to the function again.

The ellipses after

typename

, after the template type in the argument list and after the corresponding variable name in the next function call are important.

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 46 / 51

(47)

Variadic Templates: C++ Printf

Variadic Templates

While the predicates

is_integral<T>()

and

is_floating_point<T>

are predefined, the predicates

Is_C_style_string<T>()

and

Is_string<T>()

have to be defined:

t e m p l a t e<t y p e n a m e T >

b o o l I s _ C _ s t y l e _ s t r i n g () {

r e t u r n std :: is_same < T ,c o n s t c h a r* >() || std :: is_same < T ,c h a r* >() ; }

t e m p l a t e<t y p e n a m e T >

b o o l I s _ s t r i n g () {

r e t u r n std :: is_same < T ,c o n s t std :: string >() ||

std :: is_same < T , std :: string >() ; }

(48)

Variadic Templates: C++ Printf

Tuples

Another use of variadic templates are tuples, a generalization of pairs to any number of components.

Their type can be generated automatically with the help of

auto

and

std::make_tuple

.

The auxiliary function

std::get<i>

returns the i-th component of a tuple.

# include< tuple >

# include< string >

int m a i n () {

std :: tuple < std :: string ,int> t2 (" M u e l l e r ",123) ;

a u t o t = std :: m a k e _ t u p l e ( std :: s t r i n g (" M a y e r ") ,10 , 1 . 2 3 ) ; // t is of t y p e tuple < string , int , double >

std :: s t r i n g s = std :: get <0 >( t ) ; int x = std :: get <1 >( t ) ;

d o u b l e d = std :: get <2 >( t ) ; }

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 48 / 51

(49)

Variadic Templates: C++ Printf

External Templates

In projects that consist of many individual files templates are often instantiated in several places. This does not happen if they are declared with the keyword

extern

, for example in the header file extern.h:

# include< vector >

e x t e r n t e m p l a t e c l a s s std :: vector <int>;

int b l u b ( std :: vector <int>& a ) {

r e t u r n a [ 0 ] ; }

(50)

Variadic Templates: C++ Printf

Externe Templates

and also not in the main program extern.cc

# i n c l u d e" e x t e r n . h "

e x t e r n t e m p l a t e c l a s s std :: vector <int>;

int m a i n () {

std :: vector <int> x (5 ,5.) ; int y = b l u b ( x ) ;

}

Ole Klein (IWR) Object-Oriented Programming 30. Juni 2015 50 / 51

(51)

Variadic Templates: C++ Printf

Externe Templates

The actual instantiation is done explicitly in a well-defined location, in this example in the file extern2.cc:

# include< vector >

t e m p l a t e c l a s s std :: vector <int>;

It is important not to forget to link all the files together, in the simplest case by:

g++ extern2.cc extern.cc

Referenzen

ÄHNLICHE DOKUMENTE

insert(p, t) Inserts the element t in front of the one the iterator p points to, and returns an iterator that points to the inserted element.. insert(p, i, j) As above, but for

replace_copy(b,e,out,v,v2) Create copy of all elements in range [b:e) re- placing elements which are equal to v with v2 , return iterator to end of copy.

• Traits can be used to specify types and values that depend on one or more template parameters. • Policies can be used to specify parts of algorithms as

This header also contains functions that provide a thread ID and the functionality to detach threads that afterwards run as a separate program (fork).. Mutual Exclusion The header

and no exercise group, because things are still being set up, but you are welcome to attend if you have questions about the lecture or exercises or something else to discuss.. E

~List (); // clean up the list and all nodes Node* first() const; // return a pointer to the first entry Node* next( const Node* n) const; // return a pointer to the node after n

Please modify your implementation again to obtain a doubly linked list: each element should also point to its predecessor.. What is

To understand why the size of empty classes (according to standard) is as observed, consider the following class!. struct