Reputation: 149
Fairly simple question:
I have a class that uses a (variable) heuristic function to perform a certain algorithm. This heuristic function should ideally be fed to the class constructor as some sort of pointer and implement the following declaration:
int heuristic_Function(GridLocation a, GridLocation b);
What is the best way to accomplish this? Ideally I would like to avoid additional classes and keep the code fairly self-contained (and yes, I am aware of things like delegates and the strategy pattern).
(This has probably been asked hundreds of times already but in different terms)
Upvotes: 1
Views: 158
Reputation: 98485
Things get really simple if only the method that does the computations needs the function, and you can forgo storing the function in the class itself. You can then parametrize the method on the type of the passed function, and you get full flexibility:
struct Calculate {
template <typename F> int run(F && f) {
return f(1, 2);
}
};
int f1(int, int) { return 0; }
struct F2 {
int operator()(int, int) { return 0; }
};
int main() {
Calculate calc;
// pass a C function pointer
calc.run(f1);
// pass a C++98 functor
calc.run(F2());
// pass a C++11 stateless lambda
calc.run(+[](int a, int b) -> int { return a-b; });
// pass a C++11 stateful lambda
int k = 8;
calc.run([k](int a, int b) -> int { return a*b+k; });
}
You don't need to manually spell out any types, and you can pass function-like objects that can be stateful.
The power of C++11 comes from the &&
syntax. There's more to it than meets the eye. In run
's parameter, F
is a deduced type, and &&
is a universal reference. That means that, depending on the context, it acts either as an lvalue-reference we know from C++98, or as an rvalue-reference.
The +
operator applied to the lambda stresses that it is in fact stateless. Its uses forces a conversion from the abstract lambda type to a C function pointer. The type of the +[](int,int)->int {...}
expression is int(*)(int,int)
. The use of the +
operator is not necessary, I've only used it to underline the statelessness.
Upvotes: 1
Reputation: 5059
Instead of old C function pointer, I would recommend std::function
.
So you could write it like this
#include <functional>
struct algorithm{
algorithm (std::function<int(GridLocation, GridLocation)> heuristic_function) :
heuristic(heuristic_function) {}
int do_something (GridLocation a, GridLocation b){
return heuristic(a,b);
}
private:
std::function<int(GridLocation, GridLocation)> heuristic;
}
Advantages are the better readable syntax, and that the caller can use std::bind
expressions.
Or you could just take the heuristic as a template, but then you would to either make your algorithm to just a function or write the type to every new instance. See https://stackoverflow.com/a/2156899/3537677
Upvotes: 2
Reputation: 477338
Well, as you said, you could store a function pointer:
struct Algo
{
using HeurFn = int(GridLocation, GridLocation);
Algo(HeurFn * heuristic) : heuristic_(heuristic) {}
void Run()
{
// use "heuristic_(a, b)"
}
HeurFn * heuristic_;
};
Then instantiate it:
extern int my_fn(GridLocation, GridLocation);
Algo algo(my_fn);
algo.Run();
An alternative would be to pass the function directly to Run
, in which case you could make Run
a template and perhaps allow for inlining of the actual heuristic code, but you explicitly asked for the heuristic to be configured via the constructor.
Upvotes: 2