是否有一个基于宏的适配器来从类中创建一个仿函数?

时间:2013-08-11 18:35:23

标签: c++ functor

创建仿函数需要不必要的锅炉板。国家必须写4次!

struct f{
  double s; // 1st
  f(double state): s(state) {} // 2nd, 3rd and 4th
  double operator() (double x) {
    return x*s;
  }
};

是否有一个带有宏的库,它只是double functor(state)(x){ return x*state; }或类似的东西。

BOOST_FOREACH是一个运行良好的宏适配器。我正在寻找类似的东西。

任何关于如何写一个的建议也值得赞赏。

PS。使用struct for functor比绑定Class's operator() or bind a function as a functor?

更快

更新(1)

关于lambdas:

仿函数必须是模块化的,这意味着它应该可以在其他函数中重用。 lambdas必须在一个函数内 - lambda必须在main中从main和main之外的其他函数调用,不能调用main中定义的lambda。

4 个答案:

答案 0 :(得分:4)

依赖聚合初始化怎么样?只是不要声明构造函数:

struct f {
    double s;
    double operator()(double x) {
        return x * s;
    }
};

像这样使用

int main()
{       
    auto ff = f{42};
    std::cout << ff(2);
    return 0;
}

答案 1 :(得分:2)

定义所需的功能,例如,乘法,作为一个函数,然后使用std::bind()创建一个合适的函数对象:

#include <functional>

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

int main() {
    auto function = std::bind(&some_operation, 17, std::placeholders::_1);
    return function(18);
}

由于通常无法通过函数指针调用内联,因此您可能希望将函数编写为函数对象:

#include <functional>

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

int main() {
    auto function = std::bind(some_operation(), 17, std::placeholders::_1);
    return function(18);
}

下面是一个测试程序,似乎表明手工制作的函数对象和绑定的函数对象的速度大致相同,即我得到的结果是

in 90 ms, functor as a struct; result = 1.5708e+16
in 262 ms, function pointer through bind; result = 1.5708e+16
in 261 ms, function through bind; result = 1.5708e+16
in 87 ms, function object through bind; result = 1.5708e+16
in 88 ms, non-called bind with function; result = 1.5708e+16
in 88 ms, non-called bind with function pointer; result = 1.5708e+16

在使用clang version 3.4 (trunk 182411)选项优化的MacOS系统上使用最新版本的clang(更确切地说:-O2)。使用和gcc(更确切地说:gcc version 4.9.0 20130811 (experimental) (GCC))会得到类似的结果。

无论函数对象是在本地上下文中构建还是通过模板参数传递给单独的函数,似乎都有所不同。这种差异很有意思,因为我预计bind()函数的大部分用法都会导致在某处传递出结果函数对象。

代码基于https://stackoverflow.com/a/18175033/1120273

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

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

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

template <typename Function>
void measure(char const* what, Function function)
{
    const auto stp1 = high_resolution_clock::now();
    double sresult(0.0);
    for(double x=0.0; x< 1.0e8; ++x) {
        sresult += function(x);
    }
    const auto stp2 = high_resolution_clock::now();
    const auto sd = duration_cast<milliseconds>(stp2 - stp1);  
    cout << "in " << sd.count() << " ms, "; 
    cout << what << "; result = " << sresult << endl;
}


int main() {
  double state=3.1415926;

  measure("functor as a struct", fs(state));
  measure("function through bind", std::bind(&fb, _1, state));
  measure("function object through bind", std::bind(ff(), _1, state));


  {
      const auto stp1 = high_resolution_clock::now();
      double sresult(0.0);
      auto function = std::bind(fb, _1, state);
      for(double x=0.0; x< 1.0e8; ++x) {
          sresult += function(x);
      }
      const auto stp2 = high_resolution_clock::now();
      const auto sd = duration_cast<milliseconds>(stp2 - stp1);  
      cout << "in " << sd.count() << " ms, "; 
      cout << "embedded bind with function; result = " << sresult << endl;
  }
  {
      const auto stp1 = high_resolution_clock::now();
      double sresult(0.0);
      auto function = std::bind(&fb, _1, state);
      for(double x=0.0; x< 1.0e8; ++x) {
          sresult += function(x);
      }
      const auto stp2 = high_resolution_clock::now();
      const auto sd = duration_cast<milliseconds>(stp2 - stp1);  
      cout << "in " << sd.count() << " ms, "; 
      cout << "embedded bind with function pointer; result = " << sresult << endl;
  }    

  return 0;
}

答案 2 :(得分:0)

我们为此得到了lambdas:

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

在第2行单独提到状态(因为你似乎在实际表达中只计算一个)。第1行上的初始化是否值得提及是有争议的,您所需的表单不包含任何初始化,这是必需的,所以我认为这是可以接受的。

在c ++ 14中,我们将获得lambda捕获语法的扩展,允许更简洁的形式:

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

答案 3 :(得分:0)

看看BOOST_LOCAL_FUNCTION,这似乎正是您正在寻找的,因为您甚至提到了一个宏:)

double s = 42;
double BOOST_LOCAL_FUNCTION(bind& s, double x) {
  return x*s;
} BOOST_LOCAL_FUNCTION_NAME(f)

个人提示:如果你有一个现代编译器,请使用C ++ 11 lambdas。