|
Boost Users : |
Subject: Re: [Boost-users] [lambda] extending lambda functions
From: alfC (alfredo.correa_at_[hidden])
Date: 2009-03-23 20:58:39
Hi Joel,
> > the question is what do I have to do to be able to use the following
> > syntax instead
> > _1 + llnorm(_2)
>
>
> Lambdadoes not have such a facility. You can use Phoenix instead.
> Phoenix (lazy) functions allow you to do that. Phoenix is intended
> to supercedeLambda. Phoenix has been reviewed and is conditionally
> accepted into Boost after another mini-review.
Ok, I gave up with Boost.Lambda for defining such "lazy function" and
used Phoenix instead. The process was quite painless. Below is the
(working) code to define a lazy complex modulus function for those who
are interested. I have still two concerns though:
1) I am worried how the lazy function can figure out which version of
std::norm<T> to call to obtain the right result. For
std::complex<double> the lazy function works fine (double is hard
coded). But for std::complex<int> it seems that the lazy function will
always convert the result to double, I couldn't make the lazy funcion
as generic as the original std::norm<T>(std::complex<T> const& c)
function. Is it possible to improve the lazy function definition in
that respect?
(BTW, for std::complex, T == std::complex<T>::value_type)
(It is not that I think std::complex<int> is useful for something but
I thing it is a good example to ask about this).
2) I may be asking for too much sugar but is there a way to name the
function "std::norm" and not have conflicts with the standard
"std::norm<T>(std::complex<T> const& c)", the best I could do was to
call it std::norm_;
The following is the working example, compares the Lambda version with
the Phoenix version (sum5 and sum6):
#include<vector>
#include<iostream>
#include<boost/lambda/lambda.hpp>
#include<boost/lambda/bind.hpp>
#include<boost/spirit/phoenix.hpp>
#include<numeric> //for accumulate
#include<complex>
using std::cout;
using std::endl;
using std::complex;
using std::vector;
double sum_norm(double acc, complex<double> elem){
return acc+std::norm(elem);
}
namespace std{
struct norm_impl{
template <typename Arg>
struct result{
typedef double type;
};
template <typename Arg>
typename result<Arg>::type operator()(Arg ar1) const{
return std::norm(ar1);
}
};
phoenix::function<norm_impl> norm_;
}
int main(){
//create data
unsigned l=9;
vector<complex<double> > v(l);
for(int i=0; i!=v.size(); ++i) v[i]=std::complex<double>(i,1.2+i);
// using manual loop over array
double sum1=0;
for(int i=0; i!=v.size(); ++i) sum1+=norm(v[i]);
cout<<"sum1 = "<<sum1<<endl;
// using manual loop over container
double sum2=0;
for(vector<complex<double> >::const_iterator it=v.begin(); it!=v.end
(); ++it) sum2+=norm(*it);
cout<<"sum2 = "<<sum2<<endl;
//using automatic loop (accumulate) and free function
double sum3=std::accumulate(v.begin(), v.end(), double(0),
sum_norm);
cout<<"sum3 = "<<sum3<<endl;
//using accumulate and lambda with pure bind
using namespace boost::lambda;
double sum4=std::accumulate(v.begin(), v.end(), double(0),
bind(
std::plus<double>(),
_1,
bind(&std::norm<double>, _2)
)
);
cout<<"sum4 = "<<sum4<<endl;
//using accumulate and lambda
double sum5=std::accumulate(v.begin(), v.end(), double(0),
_1 + bind(&std::norm<double>,_2));
cout<<"sum5 = "<<sum5<<endl; // (cout << _1 << " = " << _2 << "\n")
("fancy print sum5", sum5);
//using accumulate and phoenix
using namespace phoenix;
double sum6=std::accumulate(v.begin(), v.end(), double(0),
arg1 + std::norm_(arg2) );
cout<<"sum6 = "<<sum6<<endl;
return 0;
}
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net