Вопрос по c++ – Проблема с указателем на функцию. Как эффективно взаимодействовать с C API (т.е. GSL) из класса C ++?

2

Этот вопрос, кажется, задавался много раз, например,here1, здесь 2 а такжеhere3.

То, что я пытаюсь сделать, это установить членfunction C-Structgsl_function к функции-члену моего класса.

class MyClass{

    double foo(double x)
    {
        return ...;
    }

    double bar(double x)
    {
        ...
        gsl_function F;
        // Problem I cant do this (compiler error)
        F.function = &(this->foo);
    }
};

Третийссылка на сайт выше предлагает решение, я думаю, что оно основано на описанном подходеhere4.

Так что мой вопрос, могу ли я сделать лучше. Есть ли более простой способ? Например, возможно с использованием функции Boost и объектов Bind.

Я оцениваю возможность использования gsl-оболочки, такой как o2scl. Но я немного разочарован, поскольку могу заплатить цену позже, если обертка не в хорошем состоянии. Какие-либо предложения?

Ваш Ответ

1   ответ
7

вы можете использовать это, чтобы удерживать указатель на рассматриваемый экземпляр. Затем используйте статическую функцию-член для пересылки функции-члену:

class MyClass
{
    double foo(double x)
    {
       ...
    }
    static double foo_wrapper(double x, void *params)
    {
        return static_cast<MyClass*>(params)->foo(x);
    }

    double bar(double x)
    {
        ...
        gsl_function F;
        F.function=&MyClass::foo_wrapper;
        F.params=this;

        // invoke GSL function passing in F
        ...
    }
};

Ты можешь сделать лучше? Есть ли более простой способ? На самом деле, нет. Любой подход, который вы выберете, будет делать это где-то под прикрытием.

Но вы можете написать простую обертку, которая скрывает часть этого:

class gsl_function_pp : public gsl_function
{
public:
    gsl_function_pp(boost::function<double(double)> const& func) : _func(func)
    {
        function=&gsl_function_pp::invoke;
        params=this;
    }
private:
    boost::function<double(double)> _func;

    static double invoke(double x, void *params)
    {
        return static_cast<gsl_function_pp*>(params)->_func(x);
    }
};

Это должно дать вам (возможно, при умеренном снижении производительности из-за нескольких косвенных воздействий) тот тип функциональности, который вам нужен:

class MyClass
{
    double foo(double x)
    {
        ...
    }

    double bar(double x)
    {
        gsl_function_pp F(boost::bind(&MyClass::foo, this, _1));
        // invoke GSL function passing in F
        ...
    }
};

Предостережение заключается в том, что вы должны убедиться, чgsl_function_pp объект остается в области действия в течение всего времени, когда GSL может вызвать его. Так что не пытайтесь установить корневой искатель / etc в одной функции (используя локальную функцию gsl_function_pp), вернитесь, а затем выполните итерации корневого поиска в другой - вы получите сбой или еще хуже.

очень проницательно, спасибо mark

Похожие вопросы