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 ]