Expression Templates¶
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 [ ]: