That was the message that Raf and me done for one of our fellow programmer’s birthday card:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
My technical ramblings.
That was the message that Raf and me done for one of our fellow programmer’s birthday card:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
While working on one of my pet projects, I’ve decided to add support to Time-based One-Time Passwords (as per RFC 6238), which is based on HMAC-Based One-Time Passwords (RFC 4226).
This is the same protocol used by Google Authenticator – in fact, you can use their iOS/Android application to generate passwords for services that use this lib.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
I’ve had to implement a factory for Python, which objects being created depending on a certain configuration object – and this is the generic solution I’ve reached to handle it:
| Python | | copy code | | ? |
| 01 | class FactoryConstructible(object): |
| 02 | def __init__(self, build_info): |
| 03 | self.build_info = build_info |
| 04 | |
| 05 | @classmethod |
| 06 | def create(cls, build_info, *args, **kwargs): |
| 07 | for c in cls.__subclasses__(): |
| 08 | if c.supports_config(config): |
| 09 | return c(config, *args, **kwargs) |
| 10 | return None |
| 11 | |
| 12 | @classmethod |
| 13 | def supports_config(cls, config): |
| 14 | raise NotImplementedError() |
A simple example of usage is shown below – naturally those classes are empty, but you can get the idea
| Python | | copy code | | ? |
| 01 | class Shape(FactoryConstructible): |
| 02 | pass |
| 03 | |
| 04 | class Square(Shape): |
| 05 | @classmethod |
| 06 | def supports_config(self, config): |
| 07 | return config == 'Square' |
| 08 | |
| 09 | class Circle(Shape): |
| 10 | @classmethod |
| 11 | def supports_config(self, config): |
| 12 | return config == 'Circle' |
| 13 | |
| 14 | circle = Shape.create('Circle') |
| 15 | square = Shape.create('Square') |
std::function is a new template added on C++11 that provides a versatile callable object wrapper: in a nutshell it can wrap around any kind of callable target, e.g., functions, non-static methods, objects with the call operator, and, naturally, lambda functions (which are either a function or an object with the () operator, anyway).
Declaring and using a wrapper is quite simple:
| C++ | | copy code | | ? |
| 01 | #include <math.h> |
| 02 | #include <iostream> |
| 03 | #include <functional> |
| 04 | |
| 05 | struct SExample |
| 06 | { |
| 07 | double operator()(double a, double b) { return a - b; } |
| 08 | }; |
| 09 | |
| 10 | int main(int, char **) |
| 11 | { |
| 12 | std::function<double(double, double)> fn; |
| 13 | SExample obj; |
| 14 | |
| 15 | fn = &pow; |
| 16 | std::cout << fn(4, 4) << std::endl; // outputs 256 |
| 17 | |
| 18 | fn = obj; |
| 19 | std::cout << fn(4, 4) << std::endl; // outputs 0 |
| 20 | |
| 21 | double x = 650; |
| 22 | fn = [&] (double a, double b) -> double { return x + a * b; }; |
| 23 | std::cout << fn(4, 4) << std::endl; // outputs 666 |
| 24 | } |
As we can see, they behave quite closely to function pointers, but with a neater syntax and the advantage of accepting pretty much anything.
One interesting feature is that if the first parameter’s type is a class/struct, the wrapper can be bound to a method of it, so std::function
| C++ | | copy code | | ? |
| 01 | #include <math.h> |
| 02 | #include <iostream> |
| 03 | #include <functional> |
| 04 | |
| 05 | struct SExample |
| 06 | { |
| 07 | bool HandleCommand(const std::string& _rCommand) |
| 08 | { |
| 09 | std::cout << "SExample::HandleCommand: " << _rCommand << std::endl; |
| 10 | return true; |
| 11 | } |
| 12 | }; |
| 13 | |
| 14 | bool HandleCommand(SExample &, const std::string &_rCommand) |
| 15 | { |
| 16 | std::cout << "::HandleCommand " << _rCommand << std::endl; |
| 17 | return true; |
| 18 | } |
| 19 | |
| 20 | int main(int, char **) |
| 21 | { |
| 22 | std::function<bool(SExample &, const std::string &)> fn; |
| 23 | SExample obj; |
| 24 | |
| 25 | fn = &HandleCommand; |
| 26 | fn(obj, "rehash"); // outputs "::HandleCommand rehash" |
| 27 | |
| 28 | fn = &SExample::HandleCommand; |
| 29 | fn(obj, "rehash"); // outputs "SExample::HandleCommand: rehash" |
| 30 | } |
Internally this is achieved by some template trickery, where the function’s first parameter’s type is separated from the other arguments, so the assignment operator can accept a member function. Naturally this doesn’t apply to static methods, which are functions with slightly different scoping/access rules.
You can check if an object is bound to a function by checking comparing it to NULL/nullptr, or simply using it as a boolean (it has an implicit cast operator defined).