smilingbuddha
smilingbuddha

Reputation: 14660

Defining functor within the body of a code

Can functors be defined locally within the body of a function?

One possible use for locally defined functors I can think of, (especially if we want to use STL algorithms), is say

we have two vectors std::vector<int>'s a and b then we can consider them in equal in many ways. i.e. a[i] = b[i] (mod loop_counter) where the loop_counter keeps changing and we test them for equality in every loop iteration.

for(int i=0 ; i<=10 ; ++i)
{
//Define binary predicate functor my_local_predicate

//Test for equality using functor local to loop
std::equal(a.begin(), a.end(), b.begin, my_local_predicate)

 // Do something if they are equal OR unequal

}

If the answer is no, how would one do the above, where the condition for equality keeps changing with every iteration?

NOTE: I tried defining a functor as follows (no for loops here) but the program failed to compile.

#include <algorithm>
#include <iostream>
#include <list>



int main() {

     class EvenOddFunctor 
  {
    int even_;
    int odd_;
    public:
    EvenOddFunctor() : even_(0), odd_(0) {}
    void operator()(int x) {
        if (x%2 == 0) even_ += x;
        else odd_ += x;
    }
    int even_sum() const { return even_; }
    int odd_sum() const { return odd_; }
  };

    EvenOddFunctor evenodd;

    int my_list[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    evenodd = std::for_each(my_list,
                  my_list+sizeof(my_list)/sizeof(my_list[0]),
                  evenodd);

    std::cout << "Sum of evens: " << evenodd.even_sum() << "\n";
    std::cout << "Sum of odds: " << evenodd.odd_sum() << std::endl;

    // output:
    // Sum of evens: 30
    // Sum of odds: 25
}

On moving the functor definition before main() the code compiled cleanly, and executed correctly.

So even if defining a functor within a body of a function seems impossible, I would like some nice STL like way of changing the equality condition at every iteration.

Upvotes: 1

Views: 275

Answers (3)

Benjamin Lindley
Benjamin Lindley

Reputation: 103703

For the first part of your question, I don't see how having a locally defined function is necessary. What you need is just a way to select different functions, which is quite simple. For example:

std::function<bool(int,int)> my_functions[10];
my_functions[0] = std::equal_to<int>();
my_functions[1] = both_divisible_by_5;
...etc

for (int i=0; i<10; ++i)
{
    if (std::equal(a.begin(), a.end(), b.begin, my_functions[i]))
    {
        ...
    }
}

Upvotes: 0

axw
axw

Reputation: 7083

(Assuming you're stuck in C++03.)

You can have your functor inherit from a template base-class defined in the top-level scope, and then refer only to the base class (e.g. using mem_fun/bind1st).

template <typename T>
struct val_functor {
    virtual ~val_functor() {}
    virtual void operator()(T x) = 0;
};

int main()
{
    class EvenOddFunctor : public val_functor<int>
    ...
    std::for_each(my_list, my_list+sizeof(my_list)/sizeof(my_list[0]),
        std::bind1st(
             std::mem_fun(&val_functor<int>::operator()),
            (val_functor<int>*)&evenodd)
    );
    ...
}

Upvotes: 1

MSN
MSN

Reputation: 54604

If you can use C++11, this would just work. In C++03, you cannot use local classes as template parameters. You could use std::accumulate instead with a local class static function (and a non-local struct to store the result in):

struct EvenOdd
{
    int even;
    int odd;
    static EvenOdd empty() { EvenOdd result= { }; return result; }
};

int main()
{
    struct EvenOddFunctor
    {
        static EvenOdd function(const EvenOdd &old_result, int x)
        {
            EvenOdd result= old_result;
            if (x%2 == 0) result.even += x;         
            else result.odd += x;
            return result;
        }
    };

    EvenOdd evenOdd= std::accumulate(..., EvenOdd::empty(), EvenOddFunctor::function);
}

Upvotes: 1

Related Questions