Loading presentation...

Present Remotely

Send the link below via email or IM

Copy

Present to your audience

Start remote presentation

  • Invited audience members will follow you as you navigate and present
  • People invited to a presentation do not need a Prezi account
  • This link expires 10 minutes after you close the presentation
  • A maximum of 30 users can follow your presentation
  • Learn more about this feature in our knowledge base article

Do you really want to delete this prezi?

Neither you, nor the coeditors you shared it with will be able to recover it again.

DeleteCancel

Make your likes visible on Facebook?

Connect your Facebook account to Prezi and let your likes appear on your timeline.
You can change this under Settings & Account at any time.

No, thanks

Expression Templates and Lazy Evaluation in C++

This talk gives a introduction to the concept of expression templates & a quick glance at boost.lambda/phoenix and proto.
by

André Bergner

on 12 April 2013

Comments (0)

Please log in to add your comment.

Report abuse

Transcript of Expression Templates and Lazy Evaluation in C++

Expression Templates &
Lazy Evaluation in C++ what are
expressions? expression tree / + sin() % a * 9 b .2 'c' nodes are operations
leaves are objects
it has no meaning on its own
it needs a context to gain meaning
it must be evaluated ( 9*b + a ) / sin( .2 % 'c' ) and a glance at boost.lambda, boost.phoenix & boost.proto what is
lazyness? examples using it creating it meta-meta:
boost.proto definitions boost.lambda boost.range blitz++ std::transform( v.begin() , v.end() , 100 + _1*_1 ); this creates a callable expression std::for_each( v.begin() , v.end() , ( ++_1 , cout << _1 ) ); for_each( v.begin(), v.end(),
if_(arg1 > 5)
[
cout << arg1 << ", "
]
); boost.phoenix the evaluation of an ex-pression is delayed until needed.

an expression or statement is defined at one place but evaluated elsewhere. auto hello = bind(printf,"hi","there");

hello(); auto add42 = _1 + 42;

add42(100); •proto::terminal<>

•proto::extends<>

•proto::default_context
callable_context<>
•proto::plus<>, proto::minus<>,…

•proto::domain<>

•proto::eval() leafes in an expression tree that infect an expression with 'protoness'

customizes expression and extends them with special functionality ( e.g., operator() )


defining own context


used to build a grammar

custom expressions, terminals, and grammars are wrapped in domains, and sub-domains


evaluirt eine expression other automatic (math.) derivation
openGL wrapper
abstracting semantic within strings that live outside of C++ (regex, lua, html, …)
... lib for
linear
algebra blitz::Array<float,2>
A(3,3), B(3,3), C(3,3);

A = 1, 0, 0,
2, 2, 2,
1, 0, 0;

B = 0, 0, 7,
0, 8, 0,
9, 9, 9;

C = A + A*B; std::vector vec = {...};

for ( auto& x : vec | reversed
| filtered( _1 != 5)
| transformed( _1*_1 ) )
{
cout << x << endl;
} another more advanced lambda library my little lambda lib my little lin.alg lib #include <iostream>
using namespace std;


template < bool >
struct eval_trait {
template < class T , class V >
static V apply ( const T& t , const V& v ) { return t(v); }
};

template <>
struct eval_trait<true> {
template < class T , class V >
static T apply ( const T& t , const V& ) { return t; }
};


struct Plus { template < class T > static T apply( const T& lhs , const T& rhs ) { return lhs + rhs; } };
struct Minus { template < class T > static T apply( const T& lhs , const T& rhs ) { return lhs - rhs; } };
struct Times { template < class T > static T apply( const T& lhs , const T& rhs ) { return lhs * rhs; } };
struct DivBy { template < class T > static T apply( const T& lhs , const T& rhs ) { return lhs / rhs; } };


template < class Lhs , class Op , class Rhs >
struct Expression
{
Expression( const Lhs& lhs , const Rhs& rhs ) : _lhs(lhs) , _rhs(rhs) {}

template < class T >
T operator() ( const T& t ) const
{
return Op::apply(
eval_trait< is_fundamental<Lhs>::value >::apply( _lhs , t ),
eval_trait< is_fundamental<Rhs>::value >::apply( _rhs , t )
);
}

private:
const Lhs& _lhs;
const Rhs& _rhs;
};


// - - - - little helper - - - - - -

template < class Lhs , class Op , class Rhs >
Expression<Lhs,Op,Rhs> make_Expression( const Lhs& lhs , const Op& op , const Rhs& rhs )
{
return Expression<Lhs,Op,Rhs>( lhs , rhs );
}


// - - - - operators - - - - - -

template < class Lhs , class Op , class Rhs , class OtherType >
Expression< Expression<Lhs,Op,Rhs> , Plus , OtherType >
operator+ ( const Expression<Lhs,Op,Rhs>& lhs , const OtherType& rhs )
{
return make_Expression( lhs , Plus() , rhs );
}

template < class Lhs , class Op , class Rhs , class OtherType >
Expression< Expression<Lhs,Op,Rhs> , Minus , OtherType >
operator- ( const Expression<Lhs,Op,Rhs>& lhs , const OtherType& rhs )
{
return make_Expression( lhs , Minus() , rhs );
}

template < class OtherType , class Lhs , class Op , class Rhs >
Expression< OtherType , Minus , Expression<Lhs,Op,Rhs> >
operator- ( const OtherType& lhs , const Expression<Lhs,Op,Rhs>& rhs )
{
return make_Expression( lhs , Minus() , rhs );
}

struct Placeholder
{
template < class Rhs >
Expression< Placeholder , Plus , Rhs > operator+ ( const Rhs& rhs )
{
return make_Expression( *this , Plus() , rhs );
}

template < class T > T operator()( const T& t ) const { return t; }
};


template < class Lhs >
Expression< Lhs , Minus , Placeholder >
operator- ( const Lhs& lhs , const Placeholder& rhs )
{
return make_Expression( lhs , Minus() , rhs );
}


Placeholder _1;




int main()
{
auto exp = 1000 - _1 + 42;
Expression< Expression<int,Minus,Placeholder> , Plus , int > exp1 = 1000 - _1 + 42 ;
Expression< int , Minus , Expression<Placeholder,Plus,int> > exp2 = 1000 - ( _1 + 42 ) ;
cout << exp(8) << endl;
} #include <iostream>
#include <array>
#include <type_traits>


namespace std {


template < bool >
struct index_trait {
template < class T , class I >
static double index ( const T & t , const I & i ) { return t[i]; }
};

template <>
struct index_trait<true> {
template < class T , class I >
static T index ( const T & t , const I & ) { return t; }
};


struct Plus { template < class T > static T apply( const T& lhs , const T& rhs ) { return lhs + rhs; } };
struct Minus { template < class T > static T apply( const T& lhs , const T& rhs ) { return lhs - rhs; } };
struct Times { template < class T > static T apply( const T& lhs , const T& rhs ) { return lhs * rhs; } };
struct DivBy { template < class T > static T apply( const T& lhs , const T& rhs ) { return lhs / rhs; } };


template < class Lhs , class Op , class Rhs >
struct Expression {

Expression( const Lhs& lhs , const Rhs& rhs ) : _lhs(lhs) , _rhs(rhs) {}

double operator[] ( size_t n ) const
{
return Op::apply(
index_trait< is_fundamental<Lhs>::value >::index( _lhs , n ),
index_trait< is_fundamental<Rhs>::value >::index( _rhs , n )
);
}

private:
const Lhs& _lhs;
const Rhs& _rhs;
};
template < class Lhs , class Op , class Rhs >
Expression<Lhs,Op,Rhs> make_Expression( const Lhs& lhs , const Op& op , const Rhs& rhs )
{
return Expression<Lhs,Op,Rhs>( lhs , rhs );
}


template < class Lhs , class Op , class Rhs , class OtherExp >
Expression< Expression<Lhs,Op,Rhs> , Plus , OtherExp >
operator+ ( const Expression<Lhs,Op,Rhs>& lhs , const OtherExp& rhs )
{
return make_Expression( lhs , Plus() , rhs );
}




template < class T , size_t N >
Expression< array<T,N> , Plus , array<T,N> > operator+ ( const array<T,N>& lhs , const array<T,N>& rhs )
{
return make_Expression( lhs , Plus() , rhs );
}

/*
template < class T , size_t N > array<T,N> operator+ ( const array<T,N>& lhs , const array<T,N> rhs )
{
array<T,N> out;
for ( size_t n = 0 ; n < N ; ++n ) out[n] = lhs[n] + rhs[n];
return out;
}
*/
}



int main()
{
std::array<int,5>
a1 = { 3,1,4,1,5 },
a2 = { 2,7,1,8,2 },
a3 = { 4,6,6,9,2 };

std::cout << (a1 + a2 + a3)[0] << std::endl;
} #include <iostream>
#include <array>
#include <boost/proto/proto.hpp>

using namespace std;
using namespace boost;

template< int I > struct placeholder {};

proto::terminal< placeholder<0> >::type const _1 = {{}};
proto::terminal< placeholder<1> >::type const _2 = {{}};


struct lambda_context : proto::callable_context< const lambda_context >
{
std::array<double,2> args;

typedef double result_type;

template<int I>
double operator() ( proto::tag::terminal , placeholder<I> ) const
{
return args[I];
}
};



int main() {

lambda_context lctx;
lctx.args[0] = 45;
lctx.args[1] = 50;

double d = proto::eval( (_2 - _1) / _2 * 100, lctx );

cout << d << endl;

proto::display_expr( (_2 - _1) / _2 * 100 );
} little lambda lib with proto #include <iostream>
#include <array>
#include <boost/proto/proto.hpp>

using namespace std;
using namespace boost;

template< int I > struct placeholder {};


struct lambda_context : proto::callable_context< const lambda_context >
{
std::array<double,2> args;

typedef double result_type;

template<int I>
double operator() ( proto::tag::terminal , placeholder<I> ) const
{
return args[I];
}
};


template<typename Expr> struct lambda_expr;

struct lambda_domain : proto::domain< proto::generator<lambda_expr> > {};

template<typename Expr>
struct lambda_expr : proto::extends<Expr, lambda_expr<Expr>, lambda_domain>
{
typedef
proto::extends<Expr, lambda_expr<Expr>, lambda_domain>
base_type;

lambda_expr( Expr const& expr = Expr() ) : base_type( expr ) {}

typedef double result_type;

double operator() ( double a1 = 0, double a2 = 0 ) const
{
lambda_context ctx;
ctx.args[0] = a1;
ctx.args[1] = a2;

return proto::eval( *this, ctx );
}
};


lambda_expr< proto::terminal< placeholder<0> >::type > const _1;
lambda_expr< proto::terminal< placeholder<1> >::type > const _2;


int main() { cout << ( (_2 - _1) / _2 * 100 )( 45 , 50 ) << endl; } usable lambda lib with proto ", " [] if_ << > 5 arg1 << cout arg1
Full transcript