1

I am learning boost fusion and am trying to take a view of a std::vector<boost::fusion::vector<int,double,double> >. The code appears simple but I appear to be running into some problems with const. I clearly misunderstand something about const and would love for someone to explain where I am going wrong.

The code:

template<int N, class T>
struct viewTraits{
    typedef typename T::value_type etype;
    typedef typename boost::fusion::result_of::as_nview<etype, N>::type netype;
    typedef std::vector<netype> result_type;
};

template <int N, typename T>
typename viewTraits<N,T>::result_type c( T const &t ) 
{
   typename viewTraits<N, T>::result_type retVal;  
    for (typename T::const_iterator it(t.begin());it<t.end();++it){
        retVal.push_back(fusion::as_nview<N>(*it));
    } 
    return retVal;
}

template <typename Container>
typename Container::value_type sum( Container const &container )
{
    typedef typename Container::value_type value_type;
    return std::accumulate( container.begin(), container.end(), value_type() );
}

int main(){
    typedef fusion::vector<int, double, double>             row;
    typedef std::vector<row>                                                container;

    container x;
    b( x, 200 );
    std::cout << sum(c<1>(x)) << std::endl;
}

The code fails to compile at retVal.push_back() because of an issue with casting const. I tried several permutations of removing and adding some const keywords but have not been successful at programming by permutation and would rather understand what I am doing.

Anyone have any thoughts? BTW the const in the function definition of sum and c must stay.

EDIT: I forgot to mention that b fills x which is a std::vector<fusion::vector<int, double, double> >

EDIT2: The corrected code:

template<int N, class T>
struct viewTraits{
    typedef typename T::value_type etype;
    typedef typename fusion::result_of::as_nview<etype, N>::type netype;
    typedef typename fusion::result_of::at_c<netype,0>::type reference;
    typedef typename boost::decay<reference>::type value_type;
    typedef std::vector<value_type> result_type;
};

template <int N, typename T>
typename viewTraits<N,T>::result_type c( T const &t )
{
    typename viewTraits<N,T>::result_type retVal;

    for(typename T::const_iterator it(t.begin()); it<t.end();++it){
        retVal.push_back(fusion::deref(fusion::begin(fusion::as_nview<N>(*it))));
    }
    return retVal;
}
rymurr
  • 444
  • 4
  • 11

2 Answers2

1

There are two immediate problems with your code:

  • you compute fusion::as_nview<N>(*it) and try to store it as if it were a fusion::result_of::as_nview<T::value_type, N>::type; in truth it is a fusion::result_of::as_nview<T::value_type const, N>::type (*it has type T::const_reference); this is the source of your const-related errors.

  • you try to accumulate the resulting views, but, as far I can tell from the Fusion docs, valid operations on such a view are mostly those of a Fusion Random Access Sequence. In particular you can't add two views together, or default construct one. Here's a lead to a possible fix (by no means the only way though), not actually tested:

    typedef typename Container::value_type view_type;
    typedef typename fusion::result_of::at_c<view_type, 0>::type reference;
    // boost::decay is from Boost.TypeTraits
    typedef typename boost::decay<reference>::type value_type;
    value_type zero = 0;
    return std::accumulate(container.begin(), container.end(), zero, add_views());
    

    where add_views is a functor that returns something in the spirit of lhs + at<0>(rhs). Note that this solution only really makes sense if you intend for c to make views of length exactly one.

Luc Danton
  • 34,649
  • 6
  • 70
  • 114
  • Regarding your second point. I am unable to change the method `sum` but am allowed to change the type of `Container`. I have not yet been able to adapt your code snippet to fit into my function `c`. Any thoughts? – rymurr Nov 21 '12 at 12:40
  • Thanks for the tips Luc, I was able to use your code snippet to sort out my question. – rymurr Nov 21 '12 at 13:10
0

Your Sequence type isn't T::value_type, it's const T::value_type. Try writing typedef const typename T::value_type etype;.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • That changed the type to `fusion::vector` which threw a number of const related compile errors – rymurr Nov 21 '12 at 11:27
  • they are too long to post here...lots of template related stuff. The essence is that your suggestion makes a `fusion::vector` instead of the `const fusion::vector` that the compiler expects. Another attempt at programming by permutation based on your suggestion has not yielded the correct type – rymurr Nov 21 '12 at 12:36