C++ 类方法的装饰器
假设我有一个函数(decorator)来度量给定函数的持续时间:C++ 类方法的装饰器,c++,C++,假设我有一个函数(decorator)来度量给定函数的持续时间: #include <unistd.h> void measure(void (*f)()) { time_t tBegin = time(NULL); f(); time_t tEnd = time(NULL); cout << "Duration: " << (tEnd - tBegin) << " sec" << endl; } 这
#include <unistd.h>
void measure(void (*f)()) {
time_t tBegin = time(NULL);
f();
time_t tEnd = time(NULL);
cout << "Duration: " << (tEnd - tBegin) << " sec" << endl;
}
这种实现会导致错误:
error: invalid use of non-static member function
在C++中有没有方法正确地实现它?它不应该修改外部函数measure
,并且测量方法完全是非静态的(它使用实例的数据)。测量应在方法运行的内部
我需要C++ 1998/2003标准的解决方案。
将measure
更改为函数模板,以允许您使用任何可调用的函数,而不仅仅是函数
在run
中使用lambda函数
我还希望使用lambda(和std::function作为度量的参数),但既然您无法更改它,那么这个想法如何:
使m()
static
向MyClass添加一个静态成员,该成员引用当前运行的MyClass实例measure
。每次调用m()
之前都必须设置此选项。另外,还要考虑线程安全性
在m()
中,您可以使用此引用访问\u d
。或者,您甚至可以将\u d
的值存储在静态成员变量中,以使其在m()
中可用。取决于您从MyClass
中实际需要什么
这种方法一次只允许测量一个调用。对于多个measure()
调用的并行执行,您可以使用线程本地存储作为在步骤2中设置的引用。因为您提到了C++03,答案是在不更改方法
的签名的情况下,您会遇到一些静态
Tom傻瓜:
我将要做的要点是为您的特定用例模拟一个C++11样式的lambda(使用返回void
的空参数列表包装对const
成员函数的调用)。您可以做一些工作使这段代码更通用一些
首先,我将发布包装器代码,然后将其分解:
template<class T, void(T::*PTR)()const, size_t I>
struct bind_member
{
typedef void(*fn_type)();
explicit bind_member(const T* _ptr)
{
ptr = _ptr;
}
static void func(void)
{
(ptr->*PTR)();
}
operator fn_type()
{
return &func;
}
private:
static const T* ptr;
};
template<class T, void(T::*PTR)()const, size_t I>
const T* bind_member<T, PTR, I>::ptr = NULL;
这是因为我们的func
类型是static
,因此它不需要类的实例,因此不会显示为成员函数指针。typedef
是为了方便起见,它指定了func
的类型,即它不接受任何参数并返回void
现在转到在Myclass
中实际调用:
void run()
{
bind_member<Myclass, &Myclass::m, 0> b(this);
measure(b);
}
void run()
{
约束成员b(本协议);
措施(b);
}
我提供了如上所述的模板参数来创建bind_成员
的实例,并将此
作为参数传递,以便bind_成员
可以调用传递的函数(m
)。我可以将&Myclass::m
作为非类型模板参数传递,因为函数指针是指针类型,是整数类型,这意味着它们有地址,所以我们可以使用模板参数来获取这些地址
最后,我们可以将b
传递给我们的measure
函数,我们就完成了
结论
如果可以的话,升级到C++11(或更高版本),并编写一个lambda,就像这里描述的其他一些答案一样。否则,请将measure
的签名更改为模板化在可调用文件上,然后我们可以更轻松地包装Myclass::m
。如果所有其他的都失败了,请使用上面的方法。在lambda中传递:代码> STD::函数< /> > ISSO不是C++ 1998/2003标准的完整代码通用需求解决方案。@我有什么办法可以改进我的答案吗?您是否找到了适用于您的用例的其他内容?OP不允许更改度量值
。抱歉。我对不修改度量值的解决方案感兴趣。
#include <iostream>
#include <time.h>
#include <unistd.h>
void measure(void (*f)()) {
time_t tBegin = time(NULL);
f();
time_t tEnd = time(NULL);
std::cout << "Duration: " << (tEnd - tBegin) << " sec" << std::endl;
}
template <typename F>
struct MeasureFunctor
{
static F* f_;
static void run(){(*f_)();}
};
template <typename F> F* MeasureFunctor<F>::f_ = nullptr;
template <typename F>
void measure(F f) {
MeasureFunctor<F>::f_ = &f;
measure(MeasureFunctor<F>::run);
}
class Myclass {
private:
double _d;
public:
Myclass(double d) : _d(d) {}
void run() {
measure([=](){m();});
}
void m() const {
usleep(1000000 * _d);
}
};
int main() {
Myclass obj(2.0);
obj.run();
return 0;
}
template<class T, void(T::*PTR)()const, size_t I>
struct bind_member
{
typedef void(*fn_type)();
explicit bind_member(const T* _ptr)
{
ptr = _ptr;
}
static void func(void)
{
(ptr->*PTR)();
}
operator fn_type()
{
return &func;
}
private:
static const T* ptr;
};
template<class T, void(T::*PTR)()const, size_t I>
const T* bind_member<T, PTR, I>::ptr = NULL;
typedef void(*fn_type)();
operator fn_type()
{
return &func;
}
void run()
{
bind_member<Myclass, &Myclass::m, 0> b(this);
measure(b);
}