Reputation: 15478
Suppose the following class calculates an arithmetic composition of two functions (represented by functors Function1 and Function2):
template<typename Function1, typename Function2, typename BinaryOp> Compose
{
// schematically:
// int operator() = Function1().operator() BinaryOp Function2.operator();
};
With this one could write, for instance,
typedef Compose<F,G,Division> F_div_G;
to obtain a new functor implementing F/G. This could be used, for instance, like this:
F f;
G g;
F_div_G f_div_g;
if( f(3)/g(3) == f_div_g(3) ) std::cout<<"... it works ..."<<std::endl;
However, by doing several compositions in this way, the code starts to become more and more unreadable.
Thus, is it possible to somehow "overload" the operator /
(and similarly other arithmetic operators) to be able to replace Compose<F,G,Division>
by F/G
? Do you know a macro or something similar which safely implements this? Or, provided that it is possible, would you discourage from doing this?
Upvotes: 0
Views: 415
Reputation: 275385
template<typename F>
struct Op {
// this is optional:
template<typename... Args>
auto operator()(Args&&...args)const{
return F{}(std::forward<Args>(args)...);
}
};
// `Op<Compose>` lets you chain these things:
template<typename LHS, typename RHS, typename Operation>
struct Compose:Op<Compose> {
template<typename... Args>
auto operator()(Args&&...args)const{
// with lots of care, perfect forwarding could be shoe horned in here, but it gets tricky:
return Operation{}(LHS{}(args...),RHS{}(args...));
}
};
// write one of these for each operator you want to handle:
struct Divide {
template<typename LHS, typename RHS>
auto operator()(LHS&& lhs,RHS&&rhs)const{
return std::forward<LHS>(lhs)()/std::forward<RHS>(rhs);
}
};
// write one of these as well for each operator you want to handle:
template<typename LHS,typename RHS>
Compose<LHS,RHS,Divide> operator/( Op<LHS> lhs, Op<RHS> rhs ) {
return {};
}
and bob is your uncle.
int main() {
auto f_div_g = Op<F>{}/Op<G>{};
auto f_div_g_div_h = Op<F>{}/Op<G>{}/Op<H>{};
}
and if you want a type:
decltype( Op<F>{}/Op<G>{} )
with maybe a std::decay
thrown in.
Upvotes: 1