How to implement a strategy template in C ++ using std :: function

I talk about the best way to implement a strategy template in C ++. So far, I have always used the standard method, where the context has a pointer to the base class of the strategy as follows:

class AbstractStrategy{ public: virtual void exec() = 0; } class ConcreteStrategyA{ public: void exec(); } class ConcreteStrategyB{ public: void exec(); } class Context{ public: Context(AbstractStrategy* strategy):strategy_(strategy){} ~Context(){ delete strategy; } void run(){ strategy->exec(); } private: AbstractStrategy* strategy_; 

Since having pointers to objects can lead to bad behavior, I was looking for a safer way to implement this pattern, and I found this question where std::function offered as the best way to handle this pattern.

Can someone explain how std::function works, maybe with an example with a strategy template?

+6
source share
4 answers

Note that the objects of one method are isomorphic to functions, and strategies are objects of only one method.

So basically you get rid of all your classes, and instead use std::function<void()> :

 class Context { public: template<typename F> explicit Context(F strategy) : strategy(std::move(strategy)) { } void run() { strategy(); } private: std::function<void()> strategy; }; 

Then you can pass any called to the Context constructor:

 Context ctx([] { std::cout << "Hello, world!\n"; }); ctx.run(); 
+7
source

This question is discussed here a little here and here . I think it depends on the specific case. Is your strategy a simple function call, for example, - I often have strategic templates in which my strategy will require several capabilities, which is poorly processed simply by having a function or functor. But if you only need a function or functor, then std::function is a convenient way to provide maximum flexibility by storing function pointers, lambda or functors. There may be performance issues that were discussed here for the initial boost implementation.

+3
source

Work on the answer

Basically, you get rid of all your classes, and instead you just use std :: function.

This generic function allows you to pass functions, lambda, functors and member functions (using std :: bind)

 class Context { public: explicit Context(std::function<void()> input) : strategy(input) { } void run() { strategy(); } private: std::function<void()> strategy; }; 

Then you can pass any called to the context constructor:

 Context ctx([] { std::cout << "Hello, world!\n"; }); ctx.run(); 

or

 void sayHelloWorld(){ std::cout << "Hello, world!\n"; } int main(){ Context ctx( sayHelloWorld ); ctx.run(); } 

or

 class SayHelloWorld{ operator()(){std::cout << "Hello, world!\n";} } int main(){ SayHelloWorld hello_world; Context ctx( hello_world ); ctx.run(); } 
+1
source

Something like that?

 #include <functional> #include <iostream> typedef std::function<int(int)> Strategy; void execute_strategy(Strategy strategy, int object) { std::cout << strategy(object) << std::endl; }; int power2(int i) { return i*i; }; int main() { execute_strategy(power2, 3); } 

I mean, the strategic pattern is the solution to the problem of the lack of actual lambda. This is allowed, so you can just pass the appropriate function.

0
source

Source: https://habr.com/ru/post/983741/


All Articles