C++ 快速绑定成员函数的方法

Posted

技术标签:

【中文标题】C++ 快速绑定成员函数的方法【英文标题】:C++ fast ways to bind member functions 【发布时间】:2014-01-26 20:47:55 【问题描述】:

我有一个class transition,里面有一个成员函数rate。我正在寻求一种方法,该方法允许我将自定义设计的 rates 插入到 transition 的瞬间中,在这些瞬间被创建之后,并且在运行时会很快!

我想优化代码以提高速度。 rate 进行简单的计算,但被程序非常频繁且多次调用。所以我想我应该避免使用虚函数......问题:在 C++ 中实现这一目标的其他最佳方法是什么(模板、boost、......)?关于特定方法的速度的评论将不胜感激。谢谢!

class transition 
public: 
  transition() : vec() 
  double rate(T_vec::iterator a)  return ...; 
private: 
  T_vec vec;
;

/* custom rate #1 */
double my_rate_1( T_vec::iterator)  
  /* do something */ 
  return ans; 


/* custom rate #2 */
double my_rate_2( T_vec::iterator)  
  /* do something */ 
  return ans; 


const int N=10;

int main (void) 

  vector<transition*> ts(N);
  for(int i=0;i!=N;++i) ts[i] = new transition;

  /* How to efficiently implement the pseudo code that follows? */  

  ts[0]->rate = my_rate_1;
  ts[1]->rate = my_rate_2;

  /* ... */     


【问题讨论】:

“名称查找”是什么意思?这是在编译时完成的。 您需要静态(编译时)解决方案(例如:模板)还是像策略模式这样的动态(运行时可配置)解决方案? @piotruś - 这是伪代码,因为我不知道如何以速度为目标首先做到这一点(在编译时插入自定义函数) @KarolyHorvath static(编译时间,模板)就可以了! 如果您需要运行时多态性,对 std::function 与裸函数指针进行基准测试,它们应该具有可比性,但 std::function 更灵活且 C++ 风格。 【参考方案1】:

至少有三种方法可以实现这一点。

选项 1 是虚拟方法。创建实例后无法绑定方法,但创建后可以将所有派生类视为transition

class transition 
    ...
    virtual double rate(T_vec::iterator a) = 0;
;

class my_transition_1 : public transition 
    ...
    double rate(T_vec::iterator a)  ... 
;
class my_transition_2 : public transition 
    ...
    double rate(T_vec::iterator a)  ... 
;

选项 2 是回调。创建对象后,您可以在运行时更改方法。这是最有活力的。在这种情况下,它的开销略高,因为迭代器有一个额外的副本构造,编译器更难优化掉间接调用。

class transition 
public:
    ....
    typedef double (*RateFunction)(T_vec::iterator a);
    void set_rate(RateFunction r)  _fun = r; 
    double rate(T_vec::iterator a)  return (*_fun)(a); 
private:
    RateFunction _fun;
;
double my_rate_1(T_vec::iterator a) 
    ...

...
transition t;
t.set_rate(my_rate_1);

选项 3 是函子模板。您必须在构建时指定所有内容,但这避免了间接调用并具有最佳性能。

template <typename Rate>
class transition 
    double rate(T_vec::iterator a) 
        return Rate()(a);
    
;
class my_rate_1 
    double operator()(T_vec::iterator a) 
        ....
    
;
class my_rate_2 
    double operator()(T_vec::iterator a) 
        ....
    
;

transition<my_rate_1> t1;
transition<my_rate_2> t2;

选项 4 不可扩展,但您避免了间接函数调用,并有机会在创建对象后设置速率。

class transition 
public:
    enum RateCode 
        RATE_1,
        RATE_2,
        ...
    
    double rate(T_vec::iterator i) 
        switch (_rate_code) 
        case RATE_1: 
            ...
            return result;
            
        case RATE_2: 
            ...
            return result;
            
        default:
            assert(false);
        
    
    void setRate(RateCode r)  _rate_code = r; 
private:
    RateCode _rate_code;

【讨论】:

鉴于每种设计模式都是可接受的,您如何按速度对这三个选项进行排名?如果rate 只包含几个算术运算,比如return vec[0]*par + vec[1]*vec[2];,那么可以预期最慢和最快的运算之间的性能差异是多少?谢谢你的好答案,顺便说一句! 选项 3 不错,但我看不出如何先创建对象/引用向量,然后再插入费率。 速度为:回调 我添加了第四个选项,它比 virtuals 更快,允许您将对象插入容器中,但不可扩展。【参考方案2】:

如果您想绑定到任意函数,请查看FastDelegate 文章。还有一个代表想法的article of a more portable implementation。

如果您可以安排您的代码,以便在编译时知道特定实例,那么这将更快,假设编译器可以很好地完成它的工作。它更快的原因是真正的委托意味着对函数指针的调用,这打破了当今 CPU 中的推测执行和流水线。

您可能还想阅读 C++11。在 C++11 中,lambda 函数(可以传递的内联编写函数)是一个重要的扩展,我希望编译器努力优化它们。

【讨论】:

以上是关于C++ 快速绑定成员函数的方法的主要内容,如果未能解决你的问题,请参考以下文章

Python绑定C++虚成员函数不能调用

提升 C++。将带有签名指针的成员函数指针传递给函数

无法在成员函数中绑定右值引用参数

UE4 C++代理(委托)

在lldb调试中调用c++函数

带有C语言绑定的静态成员函数?