By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,955 Members | 1,275 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,955 IT Pros & Developers. It's quick & easy.

Functors for complex tasks

P: 4
Hello,

I am working on a program that must perform a certain task on numeric data stored in a file. The task is given by user input from a list of possible tasks.

The file has some particular format and I have already a loop that is able to read sequentially data from the file. The question is how to operate with the data inside the loop in an efficient way.

The straight forward way (which I did) is creating as many functions as tasks are defined, each function containing the same file reading loop but with a different part inside.

To give a simple example, let's say that I want to sum all the content of the file

Expand|Select|Wrap|Line Numbers
  1. double Task1(string &filename) {
  2. // Opening part of the reading loop
  3. // Code to operate on one element at a time and perform task 1
  4. // Closing part of the reading loop
  5. }
  6.  
  7. double TaskSum(string &filename) {
  8.  
  9. double sum = 0;
  10.  
  11. // Opening part of the reading loop Identical!!!
  12. // the value of the last read element is stored in el
  13.  
  14. sum += el;
  15.  
  16. // Closing part of the reading loop Identical !!!
  17.  
  18. return sum;
  19. }
  20.  
  21.  
And this for all tasks.

However, this is a nightmare to maintain and to expand. It will be also very annoying to perform the same tasks in other file type. That's why I would like to use function objects to do it. However, I am not sure how to do it in an appropriate way. The tasks that I need to perform most of the time need to keep some persistent information. Going back to my example before, Is the following code the most efficient way to do it using function objects? Will the performance be the same as the previous case?

Expand|Select|Wrap|Line Numbers
  1. class tasks
  2.    {
  3.    public:
  4.  
  5.       virtual void do(double el)=0;  
  6.       virtual double result()=0;
  7.    };
  8.  
  9.  
  10.  
  11. class sumtask : public tasks
  12.    private:
  13.     double current;
  14.  
  15.    public:
  16.  
  17.       sumtask(): current(0) {} ;
  18.       void do(double el) { current += el; };
  19.       double result() { return current; };
  20.  
  21.    };
  22.  
  23.  
  24.  
  25. void Task(string &filename, tasks &t) {
  26. // Opening part of the reading loop Identical!!!
  27. // the value of the last read element is stored in el
  28.  
  29. t.do(el);
  30.  
  31. // Closing part of the reading loop Identical !!!
  32. return t.result();
  33. }
  34.  
  35.  
  36. int main(int argc, char* argv[]) {
  37. string f = "file.bin";
  38. sumtask t;
  39. double result = Task(f, t);
  40. }
  41.  
  42.  
I am using c++ compiled with gcc 4.0.1.

Thanks in advance,

Hernán
Nov 8 '08 #1
Share this Question
Share on Google+
9 Replies


100+
P: 424
I'm not sure what you mean by function objects since you don't use them in your example; function objects or functors overload operator(). It seems like you need to come up with a suitable abstraction for the file and the task so that the internals of the file abstraction can change depending on the file type independently to its interface as used by the task, which can then treat all file objects in the same way.
Nov 9 '08 #2

Expert 10K+
P: 11,448
Remove the reading of the file part from your tasks and read up on the 'strategy'
pattern. Basically you want to do something with a sequence of numbers. Define
an abstract class Task that represents the number processing:

Expand|Select|Wrap|Line Numbers
  1. public:
  2.    void preprocess() = 0;
  3.    void process(double x) = 0;
  4.    double postprocess() = 0;
  5.  
All your 'concrete' tasks inherit from this abstract class and implement the
methods mentioned above.

Define a 'driver' class that does the file reading; the driver class is passed one
or more task class. While reading those numbers it activates the methods
defined in the task class.

Basically your driver class doesn't know what task it calls and the task(s) doesn't
know where these numbers come from but both do what they have to do. You
can call your driver class with different tasks without changing any code at all.
This is the strategy pattern in a nutshell.

kind regards,

Jos
Nov 9 '08 #3

P: 4
I'm not sure what you mean by function objects since you don't use them in your example; function objects or functors overload operator(). It seems like you need to come up with a suitable abstraction for the file and the task so that the internals of the file abstraction can change depending on the file type independently to its interface as used by the task, which can then treat all file objects in the same way.
Thanks for the answer. This is exactly one of the problems. All examples that I have seen overloading operator() involve operations without memory, they do what they have to do in the current element and they do not remember anything of the past. Which is the efficient way to define a functor with state?

Thanks,

Hernan
Nov 9 '08 #4

P: 4
Hi Jos,

Thanks for the reply. I tried your idea and is working fine. I wrote it using iterators so I can also use vectors or other STL containers.

As I pointed out in my other reply, I still would like to know how to implement efficient functors with state. Please do not close the thread.

Thanks,

Hernan
Nov 9 '08 #5

Expert 10K+
P: 11,448
Thanks for the reply. I tried your idea and is working fine. I wrote it using iterators so I can also use vectors or other STL containers.

As I pointed out in my other reply, I still would like to know how to implement efficient functors with state. Please do not close the thread.
There's no reason at all to close this thread; it's a nice change compared to. all
the crap that is posted in here ;-)

A functor is just a class that overloads the operator() operator, so you're free to
do in that method whatever you want. I don't see the problem. Care to elaborate?

kind regards,

Jos
Nov 9 '08 #6

100+
P: 424
Which is the efficient way to define a functor with state?
I don't see why you can't have a functor class with data members, then objects of that class will be function objects which retain a state. If you need to share a state across all function objects of a certain class, then you can use a static member. This being said, I don't see how function objects are really relevant to your specific problem; implementing the suggestions in post#3 should do it.
Nov 10 '08 #7

P: 4
Thanks for all the comments and suggestions. My problem is not how to do a specific task, but how to do it in a maintainable and efficient (fast executing code) way.

While trying to understand what was bothering me, I found (again) something that I read sometime ago (and I forgot because I never used it) in Stroustrup faq

class Sum {
int val;
public:
Sum(int i) :val(i) { }
operator int() const { return val; } // extract value
int operator()(int i) { return val+=i; } // application
};

Note that a function object with an inline application operator inlines beautifully because there are no pointers involved that might confuse optimizers.
What I do not know is how to write function objects (or other classes) in a way that the mentioned optimization always take place. Of course I can profile (and indeed I do) but it would be nice to have some a priori guidelines.

Let me give another example. Let's say I need to populate a vector (vOut) with calculations that come from subsets of another one (vIn). How the subsets are defined are part of my outer loop and it is the same for all tasks. What to do with the subset changes from task to task.

So:
Expand|Select|Wrap|Line Numbers
  1. void task(vector<double> &vIn, vector<double> &vOut, tasks &t) {
  2.  
  3. // Outer Loop.
  4. // The following variables are updated in each iteration
  5. //  i is the iteration index
  6. //  start is the iterator of vIn that define the start of the subset 
  7. //  end is the iterator of vIn that define the end of the subset
  8.  
  9. vOut[i] = t(start, end);
  10.  
  11. // End of the outer loop
  12.  
  13. }
  14.  
  15.  
If t is an STL function like accumulate, the resulting binary will be the same as if I had written the code to do this operation directly inside the loop. How can I write function that keep this characteristic? For example, Will the following task also be inlined?

Expand|Select|Wrap|Line Numbers
  1. class sometask {
  2.     double val;
  3.     vector <double> v;
  4. public:
  5.     sometask (double i) :val(i) { }
  6.  
  7.     operator double() const {
  8.          return val;
  9.          }
  10.  
  11.     double operator()(iterator start, iterator end ) {        
  12.         vector <double> tmp;
  13.         set_difference(start, end, v.begin(), v.end(), tmp);
  14.         v.swap(tmp);
  15.         return val+=accumulate(v.begin(), v.end());
  16.      }
  17. };
  18.  
Regards,

H
Nov 11 '08 #8

P: 1
hi how are you?????
i hope to u all the best in your life....
please i want course in java (console application)
thanks
Nov 12 '08 #9

Expert 10K+
P: 11,448
hi how are you?????
i hope to u all the best in your life....
please i want course in java (console application)
thanks
1) This is the C and C++ forum;
2) you're hijacking someone else's thread; that is rude.

kind regards,

Jos (moderator)
Nov 12 '08 #10

Post your reply

Sign in to post your reply or Sign up for a free account.