Inspired by an article at the CUJ from Andrei Alexandrescu, I was
finally able to come up with a compose_f_gxy_hxy-adapter. I think that
it's the missing adapter to make compose.hpp complete. In the companies
production code, I needed it and used a much easier implementation with
some limitations, so it's not just a toy example.

The code attached is a first cut, tested on Intel C++ 7.1 and GCC 3.3.
The GCC 2.95.3 has problems with it I haven't solved yet (and I don't
know if it's possible at all). Anyway, I'd like to hear some comments
whether it's a good idea and should be pushed forward or if it better be
buried :)

I attached a modified compose.hpp and a new file for the same directory
where I put the type selection code, called combined_argument_type.hpp.
It needs some boostification and you need to read Andrei's article to
understand it. Really. :) Andrei's article can be found here:

http://www.cuj.com/documents/s=7996/cujcexp1904alexandr/alexandr.htm

As I put the implementation into a separate file, it should now also be
easy for boost to provide min/max (probably in utility.hpp?) like
suggested by Andrei if requested - although I'm not totally convinced
it's a good idea as IMHO min/max should have value semantics (the
currently have AFAICS) and not reference-semantics, but that's another
story.

To complete the implementation of combined_argument_type, it would help
if mpl::vector would have 16 instead of 10 arguments, but that can be
done later if there is interest in compose_f_gxy_hxy. I currently simply
removed the first types of the type-list, I've just been lazy, so don't
wonder how this should work. It won't. :)

Comments?

Regards, Daniel

// Add some nice header here... :)

#ifndef BOOST_COMBINED_ARGUMENT_TYPE_HPP
#define BOOST_COMBINED_ARGUMENT_TYPE_HPP

#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/remove_const.hpp>

#include <boost/mpl/vector.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/if.hpp>

namespace boost {

template< typename L, typename R > struct combined_argument_type
{
private:
    typedef mpl::vector<
        const bool,
        const char,
        const signed char,
        const unsigned char,
        const wchar_t,
        const short,
        const unsigned short > cutted_types; // GRRR, vector should allow 16 elements!

    typedef mpl::vector<
        const int,
        const unsigned int,
        const long,
        const unsigned long,
        const long long,
        const unsigned long long,
        const float,
        const double,
        const long double > sorted_types;
    
    typedef typename remove_const< L >::type non_const_L;
    typedef typename remove_const< R >::type non_const_R;
    
    enum {
        is_const_L = ( is_const< L >::value || !is_const< R >::value ),
        is_const_R = ( is_const< R >::value || !is_const< L >::value ),
        pos_L = mpl::find< sorted_types, const L >::type::pos::value,
        pos_R = mpl::find< sorted_types, const R >::type::pos::value,
        l2r = is_const_R && is_convertible< non_const_L&, non_const_R& >::value,
        r2l = is_const_L && is_convertible< non_const_R&, non_const_L& >::value
    };

    typedef typename mpl::if_< is_convertible< R, L >, L, R >::type T1;
    typedef typename mpl::if_c< ( pos_L != -1 ) && ( pos_L < pos_R ), R, T1 >::type T2;
    typedef typename mpl::if_c< l2r, R&, T2 >::type T3;
    
public:
    typedef typename mpl::if_c< r2l, L&, T3 >::type type;
};

} // namespace boost

#endif // BOOST_COMBINED_ARGUMENT_TYPE_HPP
/* supplementing compose function objects
 * Fri Jul 16 21:01:58 MEST 1999
 */
/* The following code example is taken from the book
 * "The C++ Standard Library - A Tutorial and Reference"
 * by Nicolai M. Josuttis, Addison-Wesley, 1999
 *
 * (C) Copyright Nicolai M. Josuttis 1999.
 * Permission to copy, use, modify, sell and distribute this software
 * is granted provided this copyright notice appears in all copies.
 * This software is provided "as is" without express or implied
 * warranty, and with no claim as to its suitability for any purpose.
 */

// See http://www.boost.org/libs/compose for Documentation.

#ifndef BOOST_COMPOSE_HPP
#define BOOST_COMPOSE_HPP

#include <functional>
#include <boost/combined_argument_type.hpp>

namespace boost {

/**********************************************************
 * type nullary_function
 * - as supplement to unary_function and binary_function
 **********************************************************/
template <class Result>
struct nullary_function {
    typedef Result result_type;
};

/**********************************************************
 * ptr_fun for functions with no argument
 **********************************************************/
template <class Result>
class pointer_to_nullary_function : public nullary_function<Result>
{
  protected:
    Result (*ptr)();
  public:
    pointer_to_nullary_function() {
    }
    explicit pointer_to_nullary_function(Result (*x)()) : ptr(x) {
    }
    Result operator()() const { 
        return ptr();
    }
};

template <class Result>
inline pointer_to_nullary_function<Result> ptr_fun(Result (*x)())
{
  return pointer_to_nullary_function<Result>(x);
}

/*********** compose_f_gx_t and compose_f_gx **********************/

/* class for the compose_f_gx adapter
 */
template <class OP1, class OP2>
class compose_f_gx_t
 : public std::unary_function<typename OP2::argument_type,
                              typename OP1::result_type>
{
  private:
    OP1 op1;    // process: op1(op2(x))
    OP2 op2;
  public:
    // constructor
    compose_f_gx_t(const OP1& o1, const OP2& o2)
     : op1(o1), op2(o2) {
    }

    // function call
    typename OP1::result_type
    operator()(const typename OP2::argument_type& x) const {
        return op1(op2(x));
    }
};

/* convenience functions for the compose_f_gx adapter
 */
template <class OP1, class OP2>
inline compose_f_gx_t<OP1,OP2>
compose_f_gx (const OP1& o1, const OP2& o2) {
    return compose_f_gx_t<OP1,OP2>(o1,o2);
}

/*********** compose_f_gx_hx_t and compose_f_gx_hx **********************/

/* class for the compose_f_gx_hx adapter
 */
template <class OP1, class OP2, class OP3>
class compose_f_gx_hx_t
 : public std::unary_function<typename OP2::argument_type,
                              typename OP1::result_type>
{
  private:
    OP1 op1;    // process: op1(op2(x),op3(x))
    OP2 op2;
    OP3 op3;
  public:
    // constructor
    compose_f_gx_hx_t (const OP1& o1, const OP2& o2, const OP3& o3)
     : op1(o1), op2(o2), op3(o3) {
    }

    // function call
    typename OP1::result_type
    operator()(const typename OP2::argument_type& x) const {
        return op1(op2(x),op3(x));
    }
};

/* convenience functions for the compose_f_gx_hx adapter
 */
template <class OP1, class OP2, class OP3>
inline compose_f_gx_hx_t<OP1,OP2,OP3>
compose_f_gx_hx (const OP1& o1, const OP2& o2, const OP3& o3) {
    return compose_f_gx_hx_t<OP1,OP2,OP3>(o1,o2,o3);
}

/*********** compose_f_gxy_t and compose_f_gxy **********************/

/* class for the compose_f_gxy adapter
 */
template <class OP1, class OP2>
class compose_f_gxy_t
 : public std::binary_function<typename OP2::first_argument_type,
                               typename OP2::second_argument_type,
                               typename OP1::result_type>
{
  private:
    OP1 op1;    // process: op1(op2(x,y))
    OP2 op2;
  public:
    // constructor
    compose_f_gxy_t (const OP1& o1, const OP2& o2)
     : op1(o1), op2(o2) {
    }

    // function call
    typename OP1::result_type
    operator()(const typename OP2::first_argument_type& x,
               const typename OP2::second_argument_type& y) const {
        return op1(op2(x,y));
    }
};

/* convenience function for the compose_f_gxy adapter
 */
template <class OP1, class OP2>
inline compose_f_gxy_t<OP1,OP2>
compose_f_gxy (const OP1& o1, const OP2& o2) {
    return compose_f_gxy_t<OP1,OP2>(o1,o2);
}

/*********** compose_f_gx_hy_t and compose_f_gx_hy **********************/

/* class for the compose_f_gx_hy adapter
 */
template <class OP1, class OP2, class OP3>
class compose_f_gx_hy_t
 : public std::binary_function<typename OP2::argument_type,
                               typename OP3::argument_type,
                               typename OP1::result_type>
{
  private:
    OP1 op1;    // process: op1(op2(x),op3(y))
    OP2 op2;
    OP3 op3;
  public:
    // constructor
    compose_f_gx_hy_t (const OP1& o1, const OP2& o2, const OP3& o3)
     : op1(o1), op2(o2), op3(o3) {
    }

    // function call
    typename OP1::result_type
    operator()(const typename OP2::argument_type& x,
               const typename OP3::argument_type& y) const {
        return op1(op2(x),op3(y));
    }
};

/* convenience function for the compose_f_gx_hy adapter
 */
template <class OP1, class OP2, class OP3>
inline compose_f_gx_hy_t<OP1,OP2,OP3>
compose_f_gx_hy (const OP1& o1, const OP2& o2, const OP3& o3) {
    return compose_f_gx_hy_t<OP1,OP2,OP3>(o1,o2,o3);
}

/*********** compose_f_g_t and compose_f_g **********************/

/* class for the compose_f_g adapter
 */
template <class OP1, class OP2>
class compose_f_g_t
 : public boost::nullary_function<typename OP1::result_type>
{
  private:
    OP1 op1;    // process: op1(op2())
    OP2 op2;
  public:
    // constructor
    compose_f_g_t(const OP1& o1, const OP2& o2)
     : op1(o1), op2(o2) {
    }

    // function call
    typename OP1::result_type
    operator()() const {
        return op1(op2());
    }
};

/* convenience functions for the compose_f_g adapter
 */
template <class OP1, class OP2>
inline compose_f_g_t<OP1,OP2>
compose_f_g (const OP1& o1, const OP2& o2) {
    return compose_f_g_t<OP1,OP2>(o1,o2);
}

/*********** compose_f_gxy_hxy_t and compose_f_gxy_hxy ******************/

/* class for the compose_f_gxy_hxy adapter
 */
template <class OP1, class OP2, class OP3>
class compose_f_gxy_hxy_t
 : public std::binary_function<typename combined_argument_type<typename OP2::first_argument_type,
                                                               typename OP3::first_argument_type>::type,
                               typename combined_argument_type<typename OP2::second_argument_type,
                                                               typename OP3::second_argument_type>::type,
                               typename OP1::result_type>
{
  private:
    OP1 op1;    // process: op1(op2(x,y),op3(x,y))
    OP2 op2;
    OP3 op3;
  public:
    // constructor
    compose_f_gxy_hxy_t (const OP1& o1, const OP2& o2, const OP3& o3)
     : op1(o1), op2(o2), op3(o3) {
    }

    // function call
    typename OP1::result_type
    operator()(const typename combined_argument_type<typename OP2::first_argument_type, typename OP3::first_argument_type>::type& x,
               const typename combined_argument_type<typename OP2::second_argument_type, typename OP3::second_argument_type>::type& y) const {
        return op1(op2(x,y),op3(x,y));
    }
};

/* convenience function for the compose_f_gxy_hxy adapter
 */
template <class OP1, class OP2, class OP3>
inline compose_f_gxy_hxy_t<OP1,OP2,OP3>
compose_f_gxy_hxy (const OP1& o1, const OP2& o2, const OP3& o3) {
    return compose_f_gxy_hxy_t<OP1,OP2,OP3>(o1,o2,o3);
}

} /* namespace boost */

#endif /*BOOST_COMPOSE_HPP*/
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Reply via email to