davidhigh
davidhigh

Reputation: 15478

C++ meta-programming: overloading of arithmetic operators for types

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

Answers (1)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

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

Related Questions