Expression Templates

Definition by Hand

Example stolen from Wikipedia.

In [1]:
!mkdir -p tmp
In [23]:
%%writefile tmp/expr-templ.cxx

#include <cstdlib>
#include <cassert>
#include <vector>
#include <iostream>

template <typename E>
class VecExpression {
  public:
    virtual ~VecExpression() { }
    double operator[](size_t i) const { return static_cast<E const&>(*this)[i];     }
    size_t size()               const { return static_cast<E const&>(*this).size(); }
};

// ----------------------------------------------

class Vec : public VecExpression<Vec> {
    std::vector<double> elems;

  public:
    double operator[](size_t i) const { return elems[i]; }
    double &operator[](size_t i)      { return elems[i]; }
    size_t size() const               { return elems.size(); }

    Vec(size_t n) : elems(n) {}

    // construct vector using initializer list 
    Vec(std::initializer_list<double>init){
        for(auto i:init)
            elems.push_back(i);
    }


    // A Vec can be constructed from any VecExpression, forcing its evaluation.
    template <typename E>
    Vec(VecExpression<E> const& vec) : elems(vec.size()) {
        for (size_t i = 0; i != vec.size(); ++i) {
            elems[i] = vec[i];
        }
    }
};

// ----------------------------------------------

template <typename E1, typename E2>
class VecSum : public VecExpression<VecSum<E1, E2> > {
    E1 const& _u;
    E2 const& _v;

public:
    VecSum(E1 const& u, E2 const& v) : _u(u), _v(v) {
        assert(u.size() == v.size());
    }

    double operator[](size_t i) const { return _u[i] + _v[i]; }
    size_t size()               const { return _v.size(); }
};

template <typename E1, typename E2>
VecSum<E1,E2>
operator+(E1 const& u, E2 const& v) {
   return VecSum<E1, E2>(u, v);
}

// ----------------------------------------------

int main()
{
    Vec v0 = {23.4,12.5,144.56,90.56};
    Vec v1 = {67.12,34.8,90.34,89.30};
    Vec v2 = {34.90,111.9,45.12,90.5};    

    Vec sum_of_vec_type = v0+v1+v2;
    
    // float x = v0+v1+v2

    for(int i=0;i<sum_of_vec_type.size();++i)
        std::cout << sum_of_vec_type[i] << std::endl;
}
Overwriting tmp/expr-templ.cxx
In [30]:
!(cd tmp; g++ expr-templ.cxx -o expr-templ)
!./tmp/expr-templ
125.42
159.2
280.02
270.36

Definition using boost::proto (I)

In [24]:
%%writefile tmp/boost-proto.cxx

#include <iostream>
#include <boost/proto/proto.hpp>
#include <boost/typeof/std/ostream.hpp>
using namespace boost;

proto::terminal< std::ostream & >::type cout_ = { std::cout };

template< typename Expr >
void evaluate( Expr const & expr )
{
    proto::default_context ctx;
    proto::eval(expr, ctx);
}

int main()
{
    evaluate( cout_ << "hello" << ',' << " world" );
    return 0;
}
Writing tmp/boost-proto.cxx
In [27]:
!(cd tmp; g++ boost-proto.cxx -o boost-proto)
!./tmp/boost-proto
hello, world

Definition using boost::proto (II)

In [32]:
%%writefile tmp/boost-proto-2.cxx

#include <boost/proto/proto.hpp>
using namespace boost;

template<int I>
struct placeholder
{};

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

int main()
{
    float x = (_2 - _1) / _2 * 100;
}
Overwriting tmp/boost-proto-2.cxx
In [33]:
!(cd tmp; g++ boost-proto-2.cxx -o boost-proto-2)
boost-proto-2.cxx: In function ‘int main()’:
boost-proto-2.cxx:14:32: error: cannot convert ‘const type’ {aka ‘const boost::proto::exprns_::expr<boost::proto::tagns_::tag::multiplies, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::divides, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::minus, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<placeholder<1> >, 0>&, const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<placeholder<0> >, 0>&>, 2>&, const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<placeholder<1> >, 0>&>, 2>&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<const int&>, 0> >, 2>’} to ‘float’ in initialization
     float x = (_2 - _1) / _2 * 100;
                                ^~~
In [ ]: