英文:
Is there a way to modify class attributes in static methods used in template decorator?
问题
我正在学习Cpp模板并尝试实现类似装饰器的功能,以便在调用`log.warn`时,在`warn`方法之上执行一些额外的代码,从而在不实际覆盖它的情况下向方法添加额外的行为。
#include <cstdio>
template <typename Func>
struct Decorator {
Func* func;
template <typename... Args>
auto operator()(Args... args) {
printf("在函数执行之前\n");
(*func)(args...);
printf("在函数执行之后\n");
}
};
class Logger{
private:
int val= 0;
static void warn(char * str, char * ptr){
printf("在warn()内部\n");
printf("%s %s\n", str, ptr);
}
void info(){printf("在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;
}
此类方法的目标是在实际调用`warn`之前打印时间。
我无法弄清楚的另一个目标是如何修改类属性的值,例如静态函数中的`val`,以便每次调用`warn`时都会增加`val`的值。
英文:
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.
答案1
得分: 3
问题在于,为了在Decorator
中增加val
,您需要在Decorator
中有一个可用的实例。这使您可以调用增量函数,您可以提供该函数。
然而,有多种方法可以实现这一点。您在自己发布的答案中提到的方法很繁琐,因为每次都需要将log
实例传递给Decorator::operator()
。
我会通过让Logger
成为自己的成员来避免这个问题。以下是一个示例C++20代码:
#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("在函数执行之前\n");
Func(mInstance, std::forward<Args>(args)...);
printf("在函数执行之后\n");
}
};
class Logger
{
private:
int val = 0;
static void warn(Logger* self, char* str, char* ptr) {
printf("在warn()内部\n");
printf("%s %s\n", str, ptr);
self->val++; // 增加类属性
}
void info() {
printf("在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;
}
注意:这是您提供的C++代码的翻译部分。
英文:
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;
}
答案2
得分: 2
如463035818_is_not_an_ai所提到的,可以通过将当前对象实例作为方法的参数来实现这一目标,最终结果如下:
class Logger {
private:
int val = 0;
static void warn(char* str, char* ptr, Logger* log) {
printf("Inside warn()\n");
printf("%s %s\n", str, ptr);
log->val += 1;
}
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, &log);
printf("%d\n", log.get_val());
return 0;
}
通过将 warn(char* str, char* ptr)
更改为 warn(char* str, char* ptr, Logger* log)
并将方法调用更改为 log.decoratorWarn(str, ptr, &log)
来实现。
英文:
As mentioned by 463035818_is_not_an_ai this can be achieved by passing the current object instance as an argument to the method the end result would become
class Logger{
private:
int val= 0;
static void warn(char * str, char * ptr, Logger * log){
printf("Inside warn()\n");
printf("%s %s\n", str, ptr);
log->val +=1;
}
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, &log);
printf("%d\n", log.get_val());
return 0;
}
by changing warn(char * str, char * ptr)
to warn(char * str, char * ptr, Logger * log)
and calling the method as log.decoratorWarn(str, ptr, &log)
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论