Hi all,
consider the following code:
std::vector<double> a(10,1.0), b(10,2.0);
BOOST_AUTO( temp , proto::as_expr<MixedDomain>(a+b+0.1) ); // is the
function proto::as_expr<MixedDomain>() needed?
temp[0];
Here the expression a +b+ 0.1 is created by the MixedDomain as it is
from the mixed example. And the operator[] is definde by:
typedef typename boost::remove_reference<
typename boost::result_of::type>::type Expr2;
typedef typename proto::result_of::eval::type result_type;
result_type
operator[](std::size_t index) const
{
Expr2 expr2 = Begin()(*this);
DereferenceCtx const deref = {};
return proto::eval(expr2, deref);
}
But the code crashes during runtime. The reason is that the number 0.1
is held by reference.
So the number 0.1 goes out of scope before i try to evaluate the
expression temp[0];
A way to solve this problem is to deep copy the expression with
deep_copy. But on the other hand i do not want to copy the two vectors a
and b.
So i am asking what is the best way to solve this problem? Can this
problem be solved by defining a Grammar that copies the number 0.1?
Or do i need to extend the deep_copy by deep_copy_if<double>()
(a+b+0.1). It should copy the terminal only if it matches the specified
type.
Thanks for your help.
B/Rgds
Kim
Here is the whole code:
//[ Mixed
///////////////////////////////////////////////////////////////////////////////
// Copyright 2008 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// This is an example of using BOOST_PROTO_DEFINE_OPERATORS to Protofy
// expressions using std::vector<> and std::list, non-proto types. It is a port
// of the Mixed example from PETE.
// (http://www.codesourcery.com/pooma/download.html).
#include <list>
#include <cmath>
#include <vector>
#include <complex>
#include <iostream>
#include <stdexcept>
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace proto = boost::proto;
namespace mpl = boost::mpl;
using proto::_;
template<typename Expr>
struct MixedExpr;
template<typename Iter>
struct iterator_wrapper
{
typedef Iter iterator;
iterator_wrapper(Iter it)
:it(it) {};
Iter it;
};
struct begin_iter :proto::callable
{
template<class Sig>
struct result;
template
struct result : proto::result_of::as_expr<
iterator_wrapper
> {};
template<class Cont>
typename result::type
operator()(Cont const& cont) const
{
iterator_wrapper<typename Cont::const_iterator> it(cont.begin());
return proto::as_expr(it);
}
};
template<typename Num>
struct num_wrapper
{
typedef Num numeric;
num_wrapper(Num num)
:num_(num)
{
//BOOST_MPL_ASSERT( (boost::is_reference<Num>) );
};
Num num_;
};
struct begin_num :proto::callable
{
template<class Sig>
struct result;
template
struct result : proto::result_of::make_expr::type
>
> {};
template<class Cont>
typename result::type
operator()(Cont const cont) const
{
//BOOST_MPL_ASSERT( (boost::is_reference::type>) );
num_wrapper<Cont> num(cont);
return proto::make_exprproto::tag::terminal(num);
}
};
// Here is a grammar that replaces vector and list terminals with their
// begin iterators
struct Begin
: proto::or_<
proto::when< proto::terminal >, begin_iter(proto::_value)>
,proto::when< proto::terminal >, begin_iter(proto::_value)>
,proto::when
,proto::when >
,proto::nary_expr<_ , proto::vararg<Begin> >
>
{};
struct DereferenceCtx
{
template
struct eval : proto::default_eval
{};
template<typename Expr>
struct eval > >
>::type
>
{
typedef typename proto::result_of::value<Expr>::type IteratorWrapper;
typedef typename IteratorWrapper::iterator iterator;
typedef typename std::iterator_traits<iterator>::reference result_type;
template<typename Expr>
result_type
operator()(Expr &expr,DereferenceCtx const&)
{
return *proto::value(expr).it;
}
};
template<typename Expr>
struct eval > >
>::type
>
{
typedef typename proto::result_of::value<Expr>::type NumWrapper;
typedef typename NumWrapper::numeric result_type;
template<typename Expr>
result_type
operator()(Expr &expr,DereferenceCtx const&)
{
return proto::value(expr).num_;
}
};
};
struct IncrementCtx
{
template
struct eval : proto::null_eval {};
template<typename Expr>
struct eval > >
>::type>
{
typedef void result_type;
template<typename Expr>
result_type
operator()(Expr& expr, IncrementCtx const & )
{
++proto::value(expr).it;
}
};
};
struct AdvanceCtx
{
std::size_t index_;
template
struct eval : proto::null_eval {};
template<typename Expr>
struct eval > >
>::type>
{
typedef void result_type;
template<typename Expr>
result_type
operator()(Expr& expr, AdvanceCtx const & ctx)
{
std::advance(proto::value(expr).it, ctx.index_);
}
};
};
// A grammar which matches all the assignment operators,
// so we can easily disable them.
struct AssignOps : proto::switch_<struct AssignOpsCases> {};
// Here are the cases used by the switch_ above.
struct AssignOpsCases
{
template struct case_ : proto::not_<_> {};
template<int D> struct case_< proto::tag::plus_assign, D > : _ {};
template<int D> struct case_< proto::tag::minus_assign, D > : _ {};
template<int D> struct case_< proto::tag::multiplies_assign, D > : _ {};
template<int D> struct case_< proto::tag::divides_assign, D > : _ {};
template<int D> struct case_< proto::tag::modulus_assign, D > : _ {};
template<int D> struct case_< proto::tag::shift_left_assign, D > : _ {};
template<int D> struct case_< proto::tag::shift_right_assign, D > : _ {};
template<int D> struct case_< proto::tag::bitwise_and_assign, D > : _ {};
template<int D> struct case_< proto::tag::bitwise_or_assign, D > : _ {};
template<int D> struct case_< proto::tag::bitwise_xor_assign, D > : _ {};
};
// A vector grammar is a terminal or some op that is not an
// assignment op. (Assignment will be handled specially.)
struct MixedGrammar
: proto::or_<
proto::when< proto::terminal , begin_num(proto::_value)>
, proto::terminal<_>
, proto::and_<
proto::nary_expr<_, proto::vararg<MixedGrammar> >
, proto::not_<AssignOps>
>
>
{};
// Expressions in the vector domain will be wrapped in VectorExpr<>
// and must conform to the VectorGrammar
struct MixedDomain
: proto::domain
{};
// Here is MixedExpr, a wrapper for expression types in the MixedDomain.
template<typename Expr>
struct MixedExpr
: proto::extends
{
explicit MixedExpr(Expr const &expr)
: proto::extends(expr)
{}
typedef typename boost::remove_reference<
typename boost::result_of::type>::type Expr2;
typedef typename proto::result_of::eval::type result_type;
result_type
operator[](std::size_t index) const
{
//BOOST_MPL_ASSERT( (boost::is_reference<Expr2>) );
Expr2 expr2 = Begin()(*this);
AdvanceCtx const adv = {index};
proto::eval(expr2, adv);
DereferenceCtx const deref = {};
return proto::eval(expr2, deref);
}
private:
// hide this:
//using proto::extends::operator [];
};
// Define a trait type for detecting vector and list terminals, to
// be used by the BOOST_PROTO_DEFINE_OPERATORS macro below.
template<typename T>
struct IsMixed
: mpl::false_
{};
template
struct IsMixed >
: mpl::true_
{};
template
struct IsMixed >
: mpl::true_
{};
namespace MixedOps
{
// This defines all the overloads to make expressions involving
// std::vector to build expression templates.
BOOST_PROTO_DEFINE_OPERATORS(IsMixed, MixedDomain)
struct assign_op
{
template
void operator ()(T &t, U const &u) const
{
t = u;
}
};
struct plus_assign_op
{
template
void operator ()(T &t, U const &u) const
{
t += u;
}
};
struct minus_assign_op
{
template
void operator ()(T &t, U const &u) const
{
t -= u;
}
};
struct sin_
{
template<typename Sig>
struct result;
template
struct result
: boost::remove_const
{};
template<typename Arg>
Arg operator ()(Arg const &a) const
{
return std::sin(a);
}
};
template<typename A>
typename proto::result_of::make_expr<
proto::tag::function
, MixedDomain
, sin_ const
, A const &
>::type sin(A const &a)
{
return proto::make_expr(sin_(), boost::ref(a));
}
template
void evaluate(FwdIter begin, FwdIter end, Expr const &expr, Op op)
{
IncrementCtx const inc = {};
DereferenceCtx const deref = {};
typename boost::result_of::type expr2 = Begin()(expr);
for(; begin != end; ++begin)
{
op(*begin, proto::eval(expr2, deref));
proto::eval(expr2, inc);
}
}
template
Vector& assign(Vector &arr,Expr const &expr)
{
evaluate(arr.begin(),arr.end(),proto::as_expr<MixedDomain>(expr),assign_op());
return arr;
}
// Add-assign to a vector from some expression.
template
std::vector &operator +=(std::vector &arr, Expr const &expr)
{
evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), plus_assign_op());
return arr;
}
// Add-assign to a list from some expression.
template
std::list &operator +=(std::list &arr, Expr const &expr)
{
evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), plus_assign_op());
return arr;
}
// Minus-assign to a vector from some expression.
template
std::vector &operator -=(std::vector &arr, Expr const &expr)
{
evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), minus_assign_op());
return arr;
}
// Minus-assign to a list from some expression.
template
std::list &operator -=(std::list &arr, Expr const &expr)
{
evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), minus_assign_op());
return arr;
}
}
int main()
{
using namespace MixedOps;
int n = 10;
std::vector<int> a,b,c,d;
std::list<double> e;
std::list f;
int i;
for(i = 0;i < n; ++i)
{
a.push_back(i);
b.push_back(2*i);
c.push_back(3*i);
d.push_back(i);
e.push_back(0.0);
f.push_back(std::complex<double>(1.0, 1.0));
}
BOOST_AUTO(temp ,c + a + 0.1 );
for(int i=0, end=n;i::const_iterator fi = f.begin();
//for (i = 0; i < n; ++i)
//{
// std::cout
// << "a(" << i << ") = " << a[i]
// << "b(" << i << ") = " << b[i]
// << "c(" << i << ") = " << c[i]
// << "d(" << i << ") = " << d[i]
// << "e(" << i << ") = " << *ei++
// << "f(" << i << ") = " << *fi++
// << std::endl;
//}
//boost::array sad;
}
//]