kirill_igum
kirill_igum

Reputation: 3993

Is there a macro-based adapter to make a functor from a class?

Creating a functor requires an unnecessary boiler plate. The state has to be written 4 times!

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

is there a library with a macro that would be just double functor(state)(x){ return x*state; } or something similar.

BOOST_FOREACH is a macro adapter that works well. I'm looking for something similar.

any suggestions on how to write one is appreciated too.

ps. using struct for functor is faster then bind Class's operator() or bind a function as a functor?

Update(1)

in regards to lambdas:

the functor has to be modular, meaning, it should be reusable in other function. lambdas have to be within a function -- lambda has to be in main to be called from main and other functions outside of main, can't call the lambda defined in main.

Upvotes: 0

Views: 388

Answers (4)

Viktor Sehr
Viktor Sehr

Reputation: 13099

Have a look at BOOST_LOCAL_FUNCTION which seems to be exactly what youre looking for, as you even mention a macro :)

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

Personal note: If you have a modern compiler, go with C++11 lambdas.

Upvotes: 0

yuri kilochek
yuri kilochek

Reputation: 13484

How about relying on aggregate initialization? Simply do not declare the constructor:

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

use it like this

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

Upvotes: 4

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153955

Define the functionality you want, e.g., you multiplication, as a function and then use std::bind() to create a suitable function object:

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

Since a call through a function pointer generally can't be inlined, you might want to write your function as a function object instead:

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

Below is a test program which seems to indicate that the speed of a hand-crafted function object and a bound function object are about the same, i.e., the results I get are

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

using a recent version of clang (more precisely: clang version 3.4 (trunk 182411)) on a MacOS system optimizing with -O2 option. Using and gcc (more precisely: gcc version 4.9.0 20130811 (experimental) (GCC)) gives similar results.

It seems it makes a difference whether the function object is build in the local context or passed via template argument to a separate function. This difference is interesting as I would expect that most of the uses of bind() a function will result in passing off the resulting function object somewhere.

The code is based on 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;
}

Upvotes: 2

yuri kilochek
yuri kilochek

Reputation: 13484

We've got lambdas for this:

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

Down to single mention of state on line 2 (as you dont seem to count one in the actual expression). Whether initialization on line 1 counts as mention is debatable, your desired form does not contain any initialization, which is required, so I assume this to be acceptable.

In c++14 we'll get extension of lambda capture syntax allowing even more terse form:

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

Upvotes: 0

Related Questions