4

Abstract

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).

Introduction

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.

Example Code

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.

Edit

I forgot to mention. I tried changing to std::function, but my original function has more than 10 arguments (It is a Fortran subroutine).

Solution

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.

0

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

7 Comments

I forgot to mention. I tried changing to std::function, but my original function has more than 10 arguments (It is a Fortran subroutine).
@AbelSiqueira: Get a better compiler (or add the flag -std=c++11): C++ 2011 supports variadic arguments and you can pass in as many arguments as you want. If this doesn't work for you, just type a version of std::function<Signature> with a suitable amount of arguments.
Function pointers have a proper time and place. They may not always be the best solution, but they definitely could not be done without in certain situations.
@DietmarKühl: Sorry, couldn't find what std::function<Signature> is, or how it works. Can you point to the direction or show an example? Can't use -std=c++11, or change compilers.
@Siqueira: std::function<T> isn't anything deeply magic (I used Signature to indicate that the template argument is actually a function signature). You can implement the same logic and provide as many arguments as you need. It is nothing complex, just mostly a typing exercise.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.