/*
This class defers a single void function call by wrapping it
in a function and calling it later. Because this is C++11 you
can pass it a lambda function.
*/
class deferred_function_call {
std::function<void(void)> the_function;
public:
inline deferred_function_call(const std::function<void(void)> &the_function) : the_function(the_function) { }
inline ~deferred_function_call() { the_function(); }
};
#define _DO_TOKEN_COMBINE__(X,Y) X##Y // helper macro
#define _TOKEN_COMBINE__(X,Y) _DO_TOKEN_COMBINE__(X,Y)
/*
What name you use to remember something to do at the end of the scope is your choice. I like
RememberTo
*/
#define _FINALLY(...) deferred_function_call _TOKEN_COMBINE__(_x_temp__,__LINE__) ([&]{ __VA_ARGS__ ; })
#define REMEMBER_TO(...) deferred_function_call _TOKEN_COMBINE__(_x_temp__,__LINE__) ([&]{ __VA_ARGS__ ; })
#define remember_to(...) deferred_function_call _TOKEN_COMBINE__(_x_temp__,__LINE__) ([&]{ __VA_ARGS__ ; })
#define RememberTo(...) deferred_function_call _TOKEN_COMBINE__(_x_temp__,__LINE__) ([&]{ __VA_ARGS__ ; })
#define defer(...) deferred_function_call _TOKEN_COMBINE__(_x_temp__,__LINE__) ([&]{ __VA_ARGS__ ; })
#define later(...) deferred_function_call _TOKEN_COMBINE__(_x_temp__,__LINE__) ([&]{ __VA_ARGS__ ; })
/*
This macro is for calling a function pair where the second call must execute.
For example:
GuardedExpression(EnterCriticalSection(&MyLock),LeaveCriticalSection(&MyLock))
*/
#define GuardedExpression(expression_start,expression_finally) expression_start; deferred_function_call _TOKEN_COMBINE__(_x_temp__,__LINE__) ([&]{ expression_finally; })
EXAMPLES
// Here is some example code that shows how to use such a macro to make your code cleanup for you
int main {
/*
Example function calls that are made in order and must execute
*/
class TCanvas {
public:
void MoveTo() {}
void LineTo() {}
void BeginDrawing() {}
void EndDrawing() {}
void MoveTo(int x, int y) {}
void LineTo(int x, int y) {}
};
void BeginDrawing(TCanvas* canvas) {
// Do stuff that happens before drawing, for example.
}
void EndDrawing(TCanvas* canvas) {
// Do stuff that happens after drawing, for example.
}
int main()
{
{
FILE *file = fopen("test_Cxx11_Finally","w");
remember_to( fclose(file); );
printf("Do stuff with the file...\n");
// read something
// write something
printf("All went well, now the file will be closed by the remember_to...\n");
}
{
/* This example assumes the existence of some TCanvas object. */
TCanvas MyCanvas;
BeginDrawing(&MyCanvas);
RememberTo(EndDrawing(&MyCanvas));
printf("Drawing some stuff!\n");
MyCanvas.MoveTo(0,0);
MyCanvas.LineTo(100,100);
}
{
/* Or you can make it call the class methods. remember_to will take any code even a block of code... */
TCanvas MyCanvas;
MyCanvas.BeginDrawing();
RememberTo(MyCanvas.EndDrawing());
printf("Drawing some stuff!\n");
MyCanvas.MoveTo(0,0);
MyCanvas.LineTo(100,100);
}
{
/* You could guard a new/delete sequence */
TCanvas* MyCanvas = new TCanvas;
RememberTo( delete MyCanvas );
printf("Executing in a guarded section!\n");
MyCanvas->MoveTo(0,0);
MyCanvas->LineTo(100,100);
}
{
/* Or like this */
GuardedExpression(TCanvas* MyCanvas = new TCanvas, delete MyCanvas);
printf("Drawing inside a guarded section!\n");
MyCanvas->MoveTo(0,0);
MyCanvas->LineTo(100,100);
}
{
/*
This naive example shows that you can use a block of code as
well in the remember_to clause.
*/
int MyCounter = 0;
RememberTo({
// Do stuff here like a normal block, this will be executed
// at the end of the enclosing scope.
if (MyCounter != 10)
printf("The code did not execute all the loop!\n");
});
// Here it tries to loop and the remember clause will detect if the
// loop did every iteration it was supposed to.
while (MyCounter < 10) {
if (MyCounter == (rand() % 30))
throw "Something happened!";
MyCounter++;
}
printf("Everything went fine!\n");
}
}
No comments:
Post a Comment