I am studying Cpp templates and experimenting how to implement a decorator like functionality so that when I call log.warn
some extra code is executed on top off the warn
method, thus resulting in an extra behavior added to the method without actually overriding it.
#include <cstdio>
template <typename Func>
struct Decorator {
Func* func;
template <typename... Args>
auto operator()(Args... args) {
printf("Before function execution\n");
(*func)(args...);
printf("After function execution\n");
}
};
class Logger{
private:
int val= 0;
static void warn(char * str, char * ptr){
printf("Inside warn()\n");
printf("%s %s\n", str, ptr);
}
void info(){printf("Inside info()\n");}
public:
Decorator<decltype(warn)> decoratedWarn{warn};
int get_val(){return val;}
};
int main(){
char str[6] = "hello";
char ptr[6] = "world";
Logger log;
log.decoratedWarn(str, ptr);
printf("%d\n", log.get_val());
return 0;
}
The goal behind such approach is to print the time before warn is actually called.
The other goal which I can't seem to figure out is how to modify the values of the class attributes such as val
in the static function so that val
is incremented every time warn
is called.
The issue is that, in order to increment the val
in Decorator
, you need an instance in Decorator
availabe. This enables you calling the increment function which you may provide.
However, there are multiple ways to achive this. The one in your own answer that you posted is tedious, becuase it requres each time the log
instance to be passed to Decorator::operator()
.
log.decoratedWarn(str, ptr, &log);
I would have avoided it by, letting the Logger
be houskeeping own members. Follwoing is an example C++20 code:
#include <cstdio>
#include <utility>
template <auto Func, typename Instance>
class Decorator
{
Instance* mInstance{ nullptr };
public:
explicit Decorator(Instance* object)
: mInstance{ object }
{}
template <typename... Args>
auto operator()(Args&&... args)
{
printf("Before function execution\n");
Func(mInstance, std::forward<Args>(args)...);
printf("After function execution\n");
}
};
class Logger
{
private:
int val = 0;
static void warn(Logger* self, char* str, char* ptr) {
printf("Inside warn()\n");
printf("%s %s\n", str, ptr);
self->val++; // Increment the class attribute
}
void info() {
printf("Inside info()\n");
}
public:
Decorator<&Logger::warn, Logger> decoratedWarn{ this };
int get_val()
{
return val;
}
};
int main()
{
char str[6] = "hello";
char ptr[6] = "world";
Logger log;
log.decoratedWarn(str, ptr);
printf("%d\n", log.get_val()); // 1
log.decoratedWarn(str, ptr);
printf("%d\n", log.get_val()); // 2
return 0;
}