1

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.

Lightness Races in Orbit
  • 358,771
  • 68
  • 593
  • 989
smilingbuddha
  • 12,744
  • 28
  • 97
  • 169
  • 1
    Which C++ compiler are you using? If it's new enough it's possible that lambdas would be an option for you. – JaredPar Jan 13 '12 at 00:22
  • possible duplicate of [Why code using local struct as parameter for STL function does not compile in g++?](http://stackoverflow.com/questions/4569928/why-code-using-local-struct-as-parameter-for-stl-function-does-not-compile-in-g) – Alexander Gessler Jan 13 '12 at 00:23
  • possible duplicate of [What is a lambda expression in C++11?](http://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11) – Flexo Jan 13 '12 at 00:23
  • @JAredPAr I am using gcc (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5 – smilingbuddha Jan 13 '12 at 00:24

3 Answers3

1

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);
}
MSN
  • 49,698
  • 7
  • 70
  • 100
1

(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)
    );
    ...
}
axw
  • 6,586
  • 1
  • 22
  • 14
0

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]))
    {
        ...
    }
}
Benjamin Lindley
  • 95,516
  • 8
  • 172
  • 256