Class's operator() or bind a function as a functor?

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-10 21:26:24

问题


There are two ways to make a functor (a function that holds a state):

  1. bind a function and define a state: bind(f, _1, state)

    double g(double x, double state) { return x+state; } function f = bind(g,_1,state);

  2. use () operator and a class:

struct f { 
  double state; 
  f(double state_):state(state_) {} 
  double operator()(double x) {return x+state;}
};

I find that bind-method is faster to write but I'm wondering if there are some hidden stones since most of the time in literature I see functor as class's () operator.


回答1:


The 3. way is a lambda expression:

auto f = [state]( double x ) { return x * state; };



回答2:


I think that bind is inspired from functional languages (as the header filename tells you). I think it's quite equivalent because it's a template function, but maybe optimized by build-in calls...

It's the first time I see this function, so I'll need to look the asm to see the difference, then I'll repost ;)

Nevertheless, It doesn't allow you to have other methods in your functor, so operator() is still needed for many uses

[EDIT] Okay, I saw the asm : bind adds a lot of code because of its templates in comparison to the "classic way". Thus, I advise you to use the strucs ways to your use (i.e. just a functor). Moreover, it's more understandable to read a such code. Bind is good if you take profit af the substitution of parameter but for simple use, it's a laser canon to cut your cheese :P [/EDIT]




回答3:


Looks like struct is the faster way to do it:

11:01:56 ~/try 
> g++ -std=c++11 main.cpp ; ./a.out
in 2265 ms, functor as a struct result = 1.5708e+16
in 31855 ms, functor through bind result = 1.5708e+16
11:02:33 ~/try 
> clang++ -std=c++11 main.cpp ; ./a.out
in 3484 ms, functor as a struct result = 1.5708e+16
in 21081 ms, functor through bind result = 1.5708e+16

the code:

#include <iostream>
#include <functional>
#include <chrono>

using namespace std;
using namespace std::placeholders;
using namespace std::chrono;

struct fs {
  double s;
  fs(double state) : s(state) {}
  double operator()(double x) {
    return x*s;
  }
};

double fb(double x, double state) {
  return x*state;
}

int main(int argc, char const *argv[]) {
  double state=3.1415926;

  const auto stp1 = system_clock::now();
  fs fstruct(state);
  double sresult;
  for(double x=0.0; x< 1.0e8; ++x) {
    sresult += fstruct(x);
  }
  const auto stp2 = high_resolution_clock::now();
  const auto sd = duration_cast<milliseconds>(stp2 - stp1);  
  cout << "in " << sd.count() << " ms, "; 
  cout << "functor as a struct result = " << sresult << endl;

  const auto btp1 = system_clock::now();
  auto fbind = bind(fb, _1, state);
  double bresult;
  for(double x=0.0; x< 1.0e8; ++x) {
    bresult += fbind(x);
  }
  const auto btp2 = high_resolution_clock::now();
  const auto bd = duration_cast<milliseconds>(btp2 - btp1);  
  cout << "in " << bd.count() << " ms, "; 
  cout << "functor through bind result = " << bresult << endl;

  return 0;
}

Update (1)

one can also have function as a function object:

struct fbs {
  double operator()(double x, double state) const {
    return x*state;
  }
};

and in the main.cpp:

  const auto bstp1 = system_clock::now();
  auto fbindstruct = bind(fbs(), _1, state);
  double bsresult;
  for(double x=0.0; x< 1.0e8; ++x) {
    bsresult += fbindstruct(x);
  }
  const auto bstp2 = high_resolution_clock::now();
  const auto bsd = duration_cast<milliseconds>(bstp2 - bstp1);  
  cout << "in " << bsd.count() << " ms, "; 
  cout << "functor through bind-struct result = " << bsresult << endl;

didn't change the speed:

> g++ -std=c++11 main.cpp ; ./a.out
hi
in 2178 ms, functor as a struct result = 1.5708e+16
in 31972 ms, functor through bind result = 1.5708e+16
in 32083 ms, functor through bind-struct result = 1.5708e+16
12:15:27 ~/try 
> clang++ -std=c++11 main.cpp ; ./a.out
hi
in 3758 ms, functor as a struct result = 1.5708e+16
in 23503 ms, functor through bind result = 1.5708e+16
in 23508 ms, functor through bind-struct result = 1.5708e+16

Update (2)

Adding optimization results in similar times:

> g++ -std=c++11 -O2 main.cpp ; ./a.out
hi
in 536 ms, functor as a struct result = 1.5708e+16
in 510 ms, functor through bind result = 1.5708e+16
in 472 ms, functor through bind-struct result = 1.5708e+16
12:31:33 ~/try 
> clang++ -std=c++11 -O2 main.cpp ; ./a.out
hi
in 388 ms, functor as a struct result = 1.5708e+16
in 419 ms, functor through bind result = 1.5708e+16
in 456 ms, functor through bind-struct result = 3.14159e+16

GCC 4.8.1 and Clang 3.3

note Clang 3.3 gives a wrong result for "bind-struct" case

Update(3)

there are more performance testing at Is there a macro-based adapter to make a functor from a class?



来源:https://stackoverflow.com/questions/18169838/classs-operator-or-bind-a-function-as-a-functor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!