Boost logo

Boost :

From: Jonathan Wang (babysloth_at_[hidden])
Date: 2003-02-13 05:10:54


Hi,

The "for-each" in mpl is used to generate codes, which apply some function to each element in a sequence. Well, I wonder if there could be more generators, "select"(a better name?) for example.

"select" is used to apply some function to a specified element in a sequence(the case in the FSM example, not each element). So it could be used to generate codes like the "if-else/switch" structure. Here's an example.

  #include <boost/mpl/range_c.hpp>
  #include "select.hpp"
  #include <boost/mpl/alias.hpp>

  struct find_helper {
  private:
    const double* X_; // array
    const double& a_; // element to be found
    int& pos_; // result, position of the given element
  public:
    find_helper(const double* X, const double& a, int& pos)
        : X_(X), a_(a), pos_(pos) {}
    bool operator ()(int i)
    {
        if(X_[i] == a_)
        {
            pos_ = i;
            return true; // "true" means it's been handled
        }
        return false; // "false" means to continue
    }
  };

  template <typename T, int N>
  struct find_element_c {
    static int do_(T* X, const T& a)
    {
        int r = N;
        mpl::select< // "select" returns true if
            mpl::range_c<int, 0, N> // the functor has been applied,
>(find_helper(X, a, r)); // otherwise false.
        return r;
    }
  };

  #include <iostream>

  int main()
  {
    double X[5] = {1.0, 2.1, 3.5, 6.6, 5.4};
    std::cout << find_element_c<double, 5>::do_(X, 3.5) << std::endl;
  }

output: 2

The generated code might look like:

  if(X[0] == 3.5)
    return 0;
  if(X[1] == 3.5)
    return 1;
  if(X[2] == 3.5)
    return 2;
  if(X[3] == 3.5)
    return 3;
  if(X[4] == 3.5)
    return 4;

The implementation of the "select" template could be rather similar to "for_each".

namespace boost {
namespace mpl {

namespace aux {

template <bool done = true>
struct select_impl
{
    template<
          typename Iterator
        , typename LastIterator
        , typename TransformFunc
        , typename F
>
    static bool execute(
          Iterator*
        , LastIterator*
        , TransformFunc*
        , F
        )
    {
        return false;
    }
};

template <>
struct select_impl<false>
{
    template<
          typename Iterator
        , typename LastIterator
        , typename TransformFunc
        , typename F
>
    static bool execute(
          Iterator*
        , LastIterator*
        , TransformFunc*
        , F f
        )
    {
        typedef typename Iterator::type item;
        typedef typename apply1<TransformFunc,item>::type arg;
    
        value_initialized<arg> x;
        if(aux::unwrap(f, 0)(boost::get(x)))
            return true;
        
        typedef typename Iterator::next iter;
        return select_impl<boost::is_same<iter,LastIterator>::value>::execute(
            (iter*)0, (LastIterator*)0, (TransformFunc*)0, f);
    }
};

} // namespace aux

template<
      typename Sequence
    , typename TransformOp
    , typename F
>
inline
bool select(F f, Sequence* = 0, TransformOp* = 0)
{
    typedef typename begin<Sequence>::type first;
    typedef typename end<Sequence>::type last;
    typedef typename lambda<TransformOp>::type transform_op;

    return aux::select_impl< boost::is_same<first,last>::value >::execute(
        (first*)0, (last*)0, (transform_op*)0, f);
}

template<
      typename Sequence
    , typename F
>
inline
bool select(F f, Sequence* = 0)
{
    return select<Sequence, identity<> >(f);
}

} // namespace mpl
} // namespace boost

 
        

Regards,
                                 

¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡Jonathan Wang
¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡babysloth_at_[hidden]
¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡2003-02-13


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk