Hello everyone,
I have stumbled over m2pq36bk97.fsf@boostpro.com in
comp.lang.c++.moderated. I had never used boost before but I always try
to solve interview questions. I found a solution that works, but I have
the feeling that there must be a more elegant solution.
The problem that was presented in the interview was the following:
typedef boost::fusion::vector row;
std::vector<row> M;
template <typename T>
typename T::value_type Accumulate (T const &t)
{
typedef typename T::value_type value_type;
return std::accumulate (t.begin (), t.end (), value_type ());
}
Provide a function fun so that
Accumulate (fun<0>(M));
computes the sum of the first column of M, or more generally
Accumulate (fun<x>(M));
computes the sum of the xth column of M.
The solution that was provided in m2pq36bk97.fsf@boostpro.com did not
work out of the box, but I was able to fix it into the following solution:
// Functor that extracts nth element of row vector.
template <unsigned N>
struct tuple_at
{
template <class Vector>
typename boost::fusion::result_of::at_c::type
operator()(Vector const& t) const
{
return boost::fusion::at_c(t);
}
};
template
auto fun(M const& x)
-> decltype(x | boost::adaptors::transformed(tuple_at<N>()))
{
return x | boost::adaptors::transformed(tuple_at<N>());
}
so that
int main () {
M.push_back(row (1, 1.0, 2.8));
M.push_back(row (2, 0.1, 2.8));
M.push_back(row (3, 0.01, 2.8));
std::cout << Accumulate(fun<1> (M));
}
prints 1.11 as expected.
However, I think that I should be able to achieve the same without the
template tuple_at. I tried using a lambda:
template
auto fun(M const& x)
-> decltype(x | boost::adaptors::transformed(
[] (typename M::value_type const& x )
{
return boost::fusion::at_c<N> (x);
}))
{
auto retval = x | boost::adaptors::transformed(
[] (typename M::value_type const& x )
{
return boost::fusion::at_c<N> (x);
});
return retval;
}
Unfortunately, this does not compile ("Lambda expression in an
unevaluated operand"). I'm also not sure whether
boost::adaptor::transformed can work with lambdas.
I also tried to generate a functor object from boost::fusion::at_c using
the following code from the internet:
template<typename T>
std::function<T> make_function (T* t) {
return { t };
}
template
auto fun (M const& x)
-> decltype(make_function(&boost::fusion::at_c))
{
auto retval = make_function(&boost::fusion::at_c );
return retval
}
but this yields an error that I can't decipher yet:
at.hpp:62:15: Implicit instantiation of undefined template
'boost::fusion::extension::at_implboost::fusion::non_fusion_tag::apply, std::__1::allocator>>, mpl_::int_<2>>'
The ideal solution would be one where I don't have to write the functor
object manually. Even more elegantly, I should be able to leave out the
return type and let the compiler figure it out automatically.
Unfortunately, I use llvm gcc 4.2, so the automatic return type
evaluation is out of reach (although boost without this feature seems to
be quite cumbersome).
Can anyone provide some insights?
Thanks in advance,
Stuart