C++ 类方法的装饰器

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; } 这

假设我有一个函数(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;
}
这种实现会导致错误:

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);
    }