Topic: common result_of for operations


Author: andy@servocomm.freeserve.co.uk (kwikius)
Date: Fri, 9 Jul 2004 05:45:03 +0000 (UTC)
Raw View
When working with different libraries it is quite common to find that
they have their own methods for determining the result_types of
operations.In nearly all cases the functionality is pretty much the
same.
Here Op is a template parameter representing the operation ie '+', '-'
etc.
A and B are my types. Hence in working with Your library I am doing
basically boilerplate:


your_library_namespace{

   your_result_of<Op,MyUDTa,MyUDTb>{


 typedef MyOp_implementation your_result_type;

  };
}

I would like to propose that the Op name should be standardised in
std, to prevent the tedious replication of what is basically
boilerplate.

We already have the proposed result_of<F(A,B)>::type . All that is now
needed is standardisation of the name Op  above for each operation.

Hence I propose this to relieve the tedium :

 result_of<operator_plus(My_TypeA,MyTypeB)>::type
 result_of<operator_divides(My_TypeA,MyTypeB)>::type
 result_of<operator_multiplies(My_TypeA,MyTypeB)>::type

 etcetera.


In other words one common interface for operations on UDT's and
fundamental types.

As further refinement  implementation of classes representing
binary_operations, and unary operations. The point of this being that
though the above is a pretty interface, it is more work to specialise
individually per UDT. (One Impl shown at the end) The following is
quick.

 template<typename L,template<typename>class Op,typename R>
 struct binary_operation{
  typedef  Whatever result_type;
  result_type operator()( /*by_const_ref_or_val*/ A,B )
 };
 template<template<typename>class Op,typename R>
 struct unary_operation{
  typedef  Whatever result_type;
  result_type operator()(...)
 };
Here the template parameter is merely a key, which resolves to one of
the binary_functions in functional.

 Hence a multiplication between an int and a double would look like
this:

 binary_operation<int,multiplies,double>::result_type.

Both this and the individual operator_xx functions above play ok with
result_of:

 result_of<binary_operation<int,multiplies,double>::type // ok
 result_of<operator_multiplies(int,double)>::type // ok

The  operator_multiplies interface does not then need to be
specialised per class but can use the implementation in
binary_operation and unary_operation:

    template<template <typename> class Op>
    struct operator_;

/* operator_ impl ... shown below */

 // these just put here to get to the point

    struct operator_logical_or : operator_<std::logical_or>{};
    struct operator_logical_and : operator_<std::logical_and>{};

    struct operator_equal_to : operator_<std::not_equal_to>{};
    struct operator_not_equal_to : operator_<std::equal_to>{};
    struct operator_greater_equal : operator_<std::greater_equal>{};
    struct operator_less_equal : operator_<std::less_equal>{};
    struct operator_greater : operator_<std::greater>{};
    struct operator_less : operator_<std::less>{};
    struct operator_minus : operator_<std::minus>{};
    struct operator_plus : operator_<std::plus>{};
    struct operator_multiplies : operator_<std::multiplies>{};
    struct operator_divides : operator_<std::divides>{};

//possibly
    struct operator_shift_left : operator_<shift_left>{};
    struct operator_shift_right : operator_<shift_right>{};
    struct operator_bit_or : operator_<bit_or>{};  //tbd
    struct operator_bit_xor : operator_<bit_xor>{};
    struct operator_bit_and : operator_<bit_and>{};

    template<template <typename> class Op>
    struct operator_{  //base class for operators

        template<typename> struct result;
        template<typename F, typename L, typename R>
        struct result<F(L,R)>
        {
            typedef typename binary_operator<
                L,
                Op,
                R
            >::result_type type;
        };


        template<typename F, typename T>
        struct result<F(T)>
        {
            typedef typename unary_operator<
                Op,
                T
            >::result_type type;
        };

        template<typename L, typename R>
        typename result<
            operator_<Op>(L,R)
        >::type
          operator()(L const&  l, R const & r)
        {
            return binary_operator<L,Op,R>()(l,r);
        }

        template<typename L, typename R>
        static
        typename result<
            operator_<Op>(L,R)
        >::type apply( L const&  l,R const&   r)
        {
            return binary_operator<L,Op,R>::apply(l, r);
        }

        template<typename T>
        typename result<
            operator_<Op>(T)
        >::type
        operator()(const T &  t)
        {
            return unary_operator<Op,T>()(t);
        }

        template<typename T>
        static
        typename result<
            operator_<Op>(T)
        >::type apply(const T& t)
        {
            return unary_operator<Op,T>::apply(t);
        }
    };

 regards
Andy Little

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]