Boost logo

Boost :

From: Aleksey Gurtovoy (alexy_at_[hidden])
Date: 2001-12-18 06:45:08


Peter Dimov wrote:
> I think that a compile-time port of boost.bind would be a
> valuable addition to MPL.

Peter, this is totally cool! The absence of full-fledged compile-time bind
was the only thing that my expression templates implementation lacked, and I
am so glad you did it! (now I can throw my own half-working version ;). In
fact, bind implements 90% of the compile-time lambda facility, and the rest
10% is below:

    template<typename T>
    struct expr_templ
    {
        typedef T type;
    };

    template<
          template<typename> class UnaryFunction
        , typename T
>
    struct expr_templ< UnaryFunction<T> >
    {
        typedef typename bind<
              boost::mpl::make_f_x<UnaryFunction>
            , typename expr_templ<T>::type
>::type type;
    };

    template<
          template<typename, typename> class BinaryFunction
        , typename T1
        , typename T2
>
    struct expr_templ< BinaryFunction<T1,T2> >
    {
        typedef typename bind<
              boost::mpl::make_f_xy<BinaryFunction>
            , typename expr_templ<T1>::type
            , typename expr_templ<T2>::type
>::type type;
    };
    
    // more specializations for ternary function template, etc.

That's all! Given the above, one can, for example, write:

    template<typename T>
    struct size_of
    {
        BOOST_STATIC_CONSTANT(std::size_t, value = sizeof(T));
        typedef boost::mpl::integral_c<std::size_t,value> type;
    };

    typedef expr_templ<
        mpl::logical_and<
              mpl::logical_not< mpl::logical_or< is_same<_1,int>,
is_same<long, _1> > >
            , mpl::greater< size_of<_1>, mpl::int_c<8> >
>
>::type f1;

    BOOST_STATIC_ASSERT((!f1::apply<int>::type::value));
    BOOST_STATIC_ASSERT((!f1::apply<long>::type::value));
    BOOST_STATIC_ASSERT((f1::apply<my>::type::value));

or

    typedef expr_templ<
        mpl::logical_or<
              mpl::logical_or< is_same<_1,_2>, is_same<_1,my> >
            , is_same<_1,_3>
>
>::type f2;

    BOOST_STATIC_ASSERT((f2::apply<int,int,void>::type::value));
    BOOST_STATIC_ASSERT((!f2::apply<long,int,void>::type::value));
    BOOST_STATIC_ASSERT((f2::apply<void,my,void>::type::value));
    BOOST_STATIC_ASSERT((f2::apply<my,int,void>::type::value));

etc.

Modifying the algorithms to apply such "parsing" internally, so they can
accept ordinary function classes as well as expression templates is a matter
of minutes..

The only caveat here is that 'is_same' class template is not exactly
'boost::is_same':

    template<typename T1, typename T2>
    struct is_same
    {
        BOOST_STATIC_CONSTANT(bool, value = false);
        typedef boost::mpl::bool_t<value> type; // '::type' interface is
"must have"
    };

    template<typename T>
    struct is_same<T,T>
    {
        BOOST_STATIC_CONSTANT(bool, value = true);
        typedef boost::mpl::bool_t<value> type;
    };

A lot of type traits class templates do not provide the '::type' interface
if they "return" boolean value, and this is a show stopper for the bind
library.

Oh, and _1, _2, etc. should be complete types - consider, for example
size_of<_1> ;). Well, actually this is a part of much bigger issue...

Aleksey


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