|
Boost Users : |
Subject: [Boost-users] Elegant solution to interview question about boost::fusion::vector
From: Stuart (DerTopper_at_[hidden])
Date: 2013-03-29 12:43:31
Hello everyone,
I have stumbled over m2pq36bk97.fsf_at_[hidden] 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<int, double, float> 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_at_[hidden] 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<const Vector,N>::type
operator()(Vector const& t) const
{
return boost::fusion::at_c<N, Vector>(t);
}
};
template <unsigned N, class M>
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 <unsigned N, class M>
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 <unsigned N, class M>
auto fun (M const& x)
-> decltype(make_function(&boost::fusion::at_c<N, const M>))
{
auto retval = make_function(&boost::fusion::at_c<N, const M> );
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_impl<boost::fusion::non_fusion_tag>::apply<const
std::__1::vector<boost::fusion::vector<int, double, float,
boost::fusion::void_, boost::fusion::void_, boost::fusion::void_,
boost::fusion::void_, boost::fusion::void_, boost::fusion::void_,
boost::fusion::void_>, std::__1::allocator<boost::fusion::vector<int,
double, float, boost::fusion::void_, boost::fusion::void_,
boost::fusion::void_, boost::fusion::void_, boost::fusion::void_,
boost::fusion::void_, boost::fusion::void_>>>, 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
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