Reputation: 75
I have a class that stores a optimization problem and runs a solver on that problem. If the solver fails I want to consider a sub-problem and solve using the same solver (and class).
An optimization problem is essencially a lot of (mathematical) functions. The problem functions are defined outside the class, but the sub-problem functions are defined inside the class, so they have different types (e.g. void (*)
and void (MyClass::*)
.
At first I thought that I could cast the member function to the non-member pointer-to-function type, but I found out that I cannot. So I'm searching for some other way.
An example code to simulate my issue:
#include <iostream>
using namespace std;
typedef void (*ftype) (int, double);
// Suppose foo is from another file. Can't change the definition
void foo (int n, double x) {
cout << "foo: " << n*x << endl;
}
class TheClass {
private:
double value;
ftype m_function;
void print (int n, double x) {
m_function(size*n, value*x);
}
public:
static int size;
TheClass () : value(1.2), m_function(0) { size++; }
void set_function (ftype p) { m_function = p; }
void call_function() {
if (m_function) m_function(size, value);
}
void call_ok_function() {
TheClass ok_class;
ok_class.set_function(foo);
ok_class.call_function();
}
void call_nasty_function() {
TheClass nasty_class;
// nasty_class.set_function(print);
// nasty_class.set_function(&TheClass::print);
nasty_class.call_function();
}
};
int TheClass::size = 0;
int main () {
TheClass one_class;
one_class.set_function(foo);
one_class.call_function();
one_class.call_ok_function();
one_class.call_nasty_function();
}
As the example suggests, the member function can't be static. Also, I can't redefine the original problem function to receive an object.
Thanks for any help.
I forgot to mention. I tried changing to std::function, but my original function has more than 10 arguments (It is a Fortran subroutine).
I made the change to std::function
and std::bind
as suggested, but did not went for the redesign of a function with more 10 arguments. I decided to create an intermediate function. The following code illustrates what I did, but with fewer variables. Thanks to all.
#include <iostream>
#include <boost/tr1/functional.hpp>
using namespace std;
class TheClass;
typedef tr1::function<void(int *, double *, double *, double *)> ftype;
// Suppose foo is from another file. Can't change the definition
void foo (int n, int m, double *A, double *x, double *b) {
// Performs matrix vector multiplication x = A*b, where
// A is m x n
}
void foo_wrapper (int DIM[], double *A, double *x, double *b) {
foo(DIM[0], DIM[1], A, x, b);
}
class TheClass {
private:
ftype m_function;
void my_function (int DIM[], double *A, double *x, double *b) {
// Change something before performing MV mult.
m_function(DIM, A, x, b);
}
public:
void set_function (ftype p) { m_function = p; }
void call_function() {
int DIM[2] = {2,2};
if (m_function) m_function(DIM, 0, 0, 0);
}
void call_nasty_function() {
TheClass nasty_class;
ftype f = tr1::bind(&TheClass::my_function, this, _1, _2, _3, _4);
nasty_class.set_function(f);
nasty_class.call_function();
}
};
int main () {
TheClass one_class;
one_class.set_function(foo_wrapper);
one_class.call_function();
one_class.call_nasty_function();
}
PS. Creating a std::function
with more than 10 variables seemed possible (compiled, but I didn't test) with
#define BOOST_FUNCTION_NUM_ARGS 15
#include <boost/function/detail/maybe_include.hpp>
#undef BOOST_FUNCTION_NUM_ARGS
But creating a std::bind
for more than 10 arguments does not seem as easy.
Upvotes: 4
Views: 332
Reputation: 146910
std::function
, std::bind
, and lambdas are what you are looking for. In short, function pointers are very bad things and should be burned in fire. In long, std::function
can store any function object which can be called with the correct signature, and you can use std::bind
or a lambda to generate a function object that calls your member function quickly and easily.
Edit: Then you will just have to roll your own std::function
equivalent that supports more than 10 arguments.
Upvotes: 3