3

I have a static function:

void E::createEP(std::list<double>* ret, double length, double (*getHeight)(double)) {
  // magic
  double sampleIntervall = //from magic

  double dist = 0;
  while (length - dist > -0.1) {
    ret->push_back(dist, (*getHeight)(dist));
    dist += sampleIntervall;
  }
}

In different calls I have two different functions to pass as getHeight():

  • A function in a database wrapper class which is not static
  • A function within the same Object of type E as createEP() (for "recreating" with different parameters), which needs to access Elements fields and can thus not be static, either.

Is it somehow possible to pass non-static functions as parameters to a static function?

If not, what would be the most elegant alternative? I don't want to duplicate the entire code in createEP().

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Niklas
  • 33
  • 4

4 Answers4

6

What you can use is a std::function. It will wrap a callable type be that a function, member function, object with an overloaded function operator. You just need to supply the signature to use. So in you case you would have

void E::createEP(std::list<double>* ret, double length, std::function<double(double)> getHeight) 

Then to bind the member function with the object you want to call it on you can use a lambda like

[&](double val){ return object.FunctionName(val); }

or std::bind like

std::bind(&ClassName::FunctionName, &object)
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • You can drop the `()` on the lambda. And I'd put the much-shorter (and possibly more peformant) lambda before the `std::bind` myself. (`std::bind` actually needs to create a data structure with both pointers, and actually invoke the member function pointer, due to `std::function` exposing access to the underlying type). – Yakk - Adam Nevraumont Oct 13 '16 at 13:58
  • @Yakk Good call on making the lambda first. – NathanOliver Oct 13 '16 at 14:01
  • what would I put as the Parameter in the lambda Expression? – Niklas Oct 13 '16 at 14:12
  • sorry, I seem not to be able to edit my comment: what would I put: [&]{ return this->getElevation(//here?);} – Niklas Oct 13 '16 at 14:16
  • @Niklas If it is a static value just hard code it. If you want the option to change it then you can use `[&](double val){ return object.function(val); }`. I updated the answer as I forgot you need to pass a value to it. – NathanOliver Oct 13 '16 at 14:18
  • @Niklas No problem. Glad to help. – NathanOliver Oct 13 '16 at 14:27
0

With c++11 the probably best option is to use std::function<double(double)> instead of the raw function pointer.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
0

std::function is really useful here

see this:

#include <functional>

using funType = std::function<void(double)>;
struct foo
{
  void bar(double d) {};
  static void call(funType f) {};
};

void foo2(double)
{
}

//...       
foo f;
//create lambda which calls member function
auto f1 = [&f](double d) { f.bar(4); };

foo::call(f1); //indirect call to member function due to lambda
foo::call(&foo2); //call to non-member function.
//...

std::function can hold a function pointer or a lambda which makes this really nice compared to c-style function pointers.

You can also call it with member functions directly but that requires bind. I think the solution with wrapping the call in a lambda looks a bit better for this.

Hayt
  • 5,210
  • 30
  • 37
0

As alternative to std::function

void E::createEP(std::list<double>* ret,
                 double length,
                 const std::function<double (double)>& getHeight)

You may use directly template

template <typename F>
void E::createEP(std::list<double>* ret,
                 double length,
                 F&& getHeight)

with body in both case

{
  // magic
  double sampleIntervall = //from magic

    double dist = 0;
    while (length - dist > -0.1) {
        ret->push_back(dist, getHeight(dist));
        dist += sampleIntervall;
    }
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302