How to pass operators as parameters

I have to load an array of doubles from a file, multiply each element by a value in a table (different values for different elements), do some work on it, invert the multiplication (that is, divide) and then save the data back to file.

Currently I implement the multiplication and division process in two separate methods. Now there is some extra work behind the scenes but apart from the specific statements where the multiplication/division occurs, the rest of the code is identical. As you can imagine, with this approach you have to be very careful making any changes. The surrounding code is not trivial, so its either a case of manually editing each method or copying changes from one method to the other and remembering to change the * and / operators.

After too many close calls I am fed up of this and would like to make a common function which implements the common logic and two wrapper functions which pass which operator to use as a parameter.

My initial approach was to use function pointers:

void MultiplyData(double data)  
{ TransformData(data, &(operator *));  } 

void DivideData(double data)  
{ TransformData(data, &(operator /));  }  

void TransformData(double data, double (*func)(double op1, double op2))  
{  /* Do stuff here... */ } 

However, I can't pass the operators as pointers (is this because it is an operator on a native type?), so I tried to use function objects. Initially I thought that multiplies and divides functors in <functional> would be ideal:

void MultiplyData(double data)  
{  
    std::multiplies<double> multFunct;  
    TransformData(data, &multFunct);  
}

void DivideData(double data)  
{  
    std::divides<double> divFunct;  
    TransformData(data, &divFunct);  
}

void TransformData(double data, std::binary_function<double, double, double> *funct)  
{  /* Do stuff here... */ } 

As you can see I was trying to use a base class pointer to pass the functor polymorphically. The problem is that std::binary_function does not declare an operator() member for the child classes to implement.

Is there something I am missing, or is the solution to implement my own functor heirarchy (which really seems more trouble than it is worth)?

Answers


Make TransformData a template function:

template <typename F>
typename F::result_type TransformData(double data, F f) { ... }

Call it thus:

double MultiplyData(double data) {
    return TransformData(data, std::multiplies<double>());
}

std::binary_function is a tagging class. It's primary purpose is not to provide a base class interface, but to inject some typedefs into functor-style classes (via inheritance), which makes them usable by other parts of the standard library.


You might want to look at using Boost.Bind or Boost.Function so that you can do something like this:

TransformData(boost::function<double(double, double)> func) {
  // use func like a function that 
  // returns a double and takes two 
  // double parameters
}

There might be a more generic solution, but in this case I'd use the fact that division is the same as multiplication by the inverse, i.e. x/C == x * (1/C).


First of all: TransformData should be template function that uses static polymorphism rather then dynamic. binary_function is only "tag", these multiples and divides do not overload its operator() - because it does not have one.

template<typename Func>
void TransformData(double *data,Func f)
{
   for(int i=0;i<some_data_size;i++)
      data[i]=f(data[i],otherdata[i]);
}

And now f would be used correctly. multiples, divides or any other.

And then you call

TransformData(data,std::multiples<double>());
TransformData(data,std::divides<double>());
TransformData(data,some_other_functional);

I'd consider using std::transform instead of your TransformData. As you've written it, TransformData requires tighter coupling (inheritance) than is really necessary in this case. If you use inheritance, it means your multiply and divide functions would have to be virtual, which (in the case of something as simple as multiplication or division) would probably add significant overhead.

std::transform doesn't require a virtual function call. With it, the function to be invoked is a template parameter, which means as long as whatever you pass supports the normal syntax for a function call (i.e. putting parentheses after the name) it'll work.

Since transform also uses iterators, you can apply it directly to the input as you read from the file:

transform(istream_iterator<double>(infile),
          istream_iterator<double>(),
          coefficients.begin(),
          data.begin(), 
          std::multiply);

// do the other work on data

transform(data.begin(), 
          data.end(), 
          coefficients.begin(), 
          ostream_iterator<double>(outfile),
          std::divide);

Another possibility to consider would be to use std::valarrays instead. With an valarray, the code could be as simple as: data *= coefficients; and data /= coefficients;


As Marcelo suggested, except that I would not pass the function object as a parameter, but construct internally as:

template <typename TransformationFunctor>
TransformData(double data) 
{  
    TransformationFunctor f;
    ...
}

and then use as:

MultiplyData(double data)
{ 
    TransformData< std::multiplies<double> >(data); 
}

Need Your Help

Convert.ChangeType() on EntityObject

mysql entity-framework entityobject

I'm working on MySQL using .Net Connector 6.3.6 and created Entity models on VS 2010. I'm planning to write a generic method that would add an EntityObject to its corresponding table. Here is how it

MVVM with WPF using LINQtoSQL in a DAL along with a BLL

wpf linq-to-sql mvvm

My goal is to have an app that is using WPF and is a 3 tier architecture. UI, BLL, and DAL...I'd like to use the MVVM but I'm not sure how that works with a 3 tier architecture or if it is something