common result_of for operations

1 view
Skip to first unread message

kwikius

unread,
Jul 9, 2004, 1:45:03 AM7/9/04
to
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...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

Reply all
Reply to author
Forward
0 new messages