Reputation: 14660
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
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
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
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