Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass operator as function template parameter

I have to overload the basic arithmetic operators for some very complicated objects I've made. So far, I've successfully implemented operator*; now I need operator+, etc. The code for operator* is very large, but the only difference between operator* and operator+ will be one line where I use + instead of * on some complex numbers. This line will be inside of a loop that gets called many many times, so I want it to be efficient, which would seem to imply no function pointers. (Correct me if I'm wrong.)

This seems like a perfect use for templates. But I'm at a loss as to the correct syntax. I'm thinking something like this inside the ComplicatedObject class definition:

template <typename ComplexBinaryOp>
ComplicatedObject BinaryOp(const ComplicatedObject& B) const {
  // Do lots of stuff
  for(unsigned int i=0; i<OneBazillion; ++i) {
    // Here, the f[i] are std::complex<double>'s:
    C.f[i] = ComplexBinaryOp(f[i], B.f[i]);
  }
  // Do some more stuff
  return C;
}

inline ComplicatedObject operator*(const ComplicatedObject& B) const {
  return BinaryOp<std::complex::operator*>(B);
}

inline ComplicatedObject operator+(const ComplicatedObject& B) const {
  return BinaryOp<std::complex::operator+>(B);
}

This question is related: "function passed as template argument". But the functions passed as the template arguments are not operators.

I've fiddled with the syntax every way I can think of, but the compiler always complains of bad syntax. How should I do this?

Edit:

For clarity, I include the complete solution in terms of my code above, along with the additional generalizations people may need:

template <typename ComplexBinaryOp>
ComplicatedObject BinaryOp(const ComplicatedObject& B) const {
  // Do lots of stuff
  for(unsigned int i=0; i<OneBazillion; ++i) {
    // Here, the f[i] are std::complex<double>'s:
    C.f[i] = ComplexBinaryOp()(f[i], B.f[i]); // Note extra ()'s
  }
  // Do some more stuff
  return C;
}

inline ComplicatedObject operator+(const ComplicatedObject& B) const {
  return BinaryOp<std::plus<std::complex<double> > >(B);
}

inline ComplicatedObject operator-(const ComplicatedObject& B) const {
  return BinaryOp<std::minus<std::complex<double> > >(B);
}

inline ComplicatedObject operator*(const ComplicatedObject& B) const {
  return BinaryOp<std::multiplies<std::complex<double> > >(B);
}

inline ComplicatedObject operator/(const ComplicatedObject& B) const {
  return BinaryOp<std::divides<std::complex<double> > >(B);
}
like image 890
Mike Avatar asked Jun 26 '13 03:06

Mike


2 Answers

I think std::plus<std::complex> and std::multiplies<std::complex> are what you're looking for, but I'm not 100% sure I understand your question (is your code snippet within a class you aren't showing us?)

like image 157
Mark B Avatar answered Sep 28 '22 06:09

Mark B


You have two options. Pass the function at runtime:

#include <functional>

template <typename ComplexBinaryOp>
ComplicatedObject BinaryOp(const ComplicatedObject& B, ComplexBinaryOp op) const {
  // ...
    C.f[i] = op(f[i], B.f[i]);
  // ...
}

// functor wrapping member function pointer
BinaryOp(B, std::mem_fn(&std::complex<double>::operator+));

// standard-issue functor
BinaryOp(B, std::plus<std::complex<double>>());

Or pass it at compile-time:

// or another floating-point type
typedef double (*ComplexBinaryOp)(double, double);

template <ComplexBinaryOp op>
ComplicatedObject BinaryOp(const ComplicatedObject& B) const {
  // ...
    C.f[i] = op(f[i], B.f[i]);
  // ...
}

// non-member function
template<class T>
std::complex<T> add_complex(const std::complex<T>& a, const std::complex<T>& b) {
  return a + b;
}

// non-member function pointer
BinaryOp<add_complex<double>>(B);

I believe you can do the same with member function pointers as well by changing the definition of ComplexBinaryOp.

like image 30
Jon Purdy Avatar answered Sep 28 '22 06:09

Jon Purdy