【问题标题】:Class's operator() or bind a function as a functor?类的 operator() 或将函数绑定为仿函数?
【发布时间】:2013-08-11 07:42:37
【问题描述】:

有两种方法可以制作仿函数(一个保存状态的函数):

  1. 绑定一个函数并定义一个状态:bind(f, _1, state)

    double g(double x, double state) { 返回x+状态; } 函数 f = bind(g,_1,state);

  2. 使用() 运算符和一个类:

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

我发现bind-method 写起来更快,但我想知道是否有一些隐藏的石头,因为在文学中的大部分时间我都将函子视为类的() 运算符。

【问题讨论】:

  • 您的std::bind(f, _1, state) 中的f 是什么?
  • std::bind 所做的基本上是在第二种情况下创建一个对象。所以实际上并没有太大的区别。第二个在书籍等中更为常见,因为std::bind 和 C++11 仍然很新。
  • @KennyTM 我编辑了示例
  • 由于这是用 C+11 标记的,还有另一种方式,lambda 函数与捕获。

标签: performance c++11 coding-style functor


【解决方案1】:

3.方式是lambda表达式:

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

【讨论】:

  • 这是一个很好的快速解决方案,但我不知道您将如何在不同的功能中使用它。似乎不是模块化的——你必须在函数的定义中定义状态。在另外两个中,您在单独的模块中定义函数并在初始化时定义状态。
【解决方案2】:

我认为bind 的灵感来自函数式语言(正如头文件名告诉你的那样)。 我认为它是相当等价的,因为它是一个模板函数,但可能通过内置调用进行了优化......

这是我第一次看到这个功能,所以我需要看一下asm看看有什么不同,然后我会重新发布;)

尽管如此,它不允许您在仿函数中使用其他方法,因此许多用途仍然需要operator()

[编辑] 好的,我看到 asm : bind 与“经典方式”相比,由于它的模板添加了很多代码。因此,我建议您使用 strucs 方式来使用(即只是一个仿函数)。此外,阅读这样的代码更容易理解。 如果您从参数替换中获利,则绑定很好,但为了简单使用,它是切割奶酪的激光佳能:P [/EDIT]

【讨论】:

  • 如果我使用 -O2 优化,我将获得相同的速度。您是否在优化或不优化的情况下查看 asm。感谢收看
【解决方案3】:

看起来struct 是更快的方法:

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

代码:

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

更新(1)

一个函数也可以作为函数对象:

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

在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;

没有改变速度:

> 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

更新(2)

在相似时间添加优化结果:

> 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 和 Clang 3.3

注意 Clang 3.3 对“bind-struct”的情况给出了错误的结果

更新(3)

Is there a macro-based adapter to make a functor from a class? 有更多性能测试

【讨论】:

  • 您的基准测试并不重要,因为有很多情况:bind 可以与可变数量的参数一起使用,要详尽无遗,您需要根据参数的数量进行检查。但是,这还不是全部,还有一些不是功能的用途。见cplusplus.com/reference/functional/bind
  • 这只是为了获得一个初步的想法。从答案来看,我会使用 bind 因为编写原型更快,然后如果我需要进一步优化,我会测量其他选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-02
  • 1970-01-01
  • 1970-01-01
  • 2010-12-22
相关资源
最近更新 更多