使用void *和void **调用灵活的函数

时间:2017-01-24 11:25:51

标签: c++ pointers void-pointers

我希望编写一个函数,该函数使用double函数的返回值但是/我想在函数调用期间选择这个双函数。我的想法是:

#include <iostream>

double linea(double a, double b, double x);
double parabola(double a, double b, double c, double x);

void konjgrad(double (*function)(void** params), void** params);

double linea(double a, double b, double x){
    return a*x+b;
}

double parabola(double a, double b, double c, double x){
    return a*x*x+b*x+c;
}

void konjgrad(double (*function)(void** params), void** params){
    double d; 
    d=function(params);
    std::cout<<d<<std::endl;
}

int main(){
    konjgrad(linea(1.6,5.1,2.6));    
    konjgrad(parabola(2.4,3.1,4,2.6));

    return 0;
}

但我陷入了指针的迷宫中。有谁有想法,如何解决问题?

2 个答案:

答案 0 :(得分:4)

您可以使用variadic templatesperfect-forwarding来提供所需的灵活性,而无需任何额外的运行时间开销:

template <typename TF, typename... TArgs>
void konjgrad(TF&& f, TArgs&&... args)
{
    double d;
    d = std::forward<TF>(f)(std::forward<TArgs>(args)...);
    std::cout<<d<<std::endl;
}
然后可以按如下方式调用

konjgrad

konjgrad(linea, 1.6, 5.1, 2.6);    
konjgrad(parabola, 2.4, 3.1, 4, 2.6);

wandbox example

或者,您可以使用lambda expressions并将参数绑定的负担放在调用者身上:

template <typename TF>
void konjgrad(TF&& f)
{
    double d;
    d = std::forward<TF>(f)();
    std::cout<<d<<std::endl;
}
然后可以按如下方式调用

konjgrad

konjgrad([]{ return linea(1.6, 5.1, 2.6); });    
konjgrad([]{ return parabola(2.4, 3.1, 4, 2.6); });

wandbox example

答案 1 :(得分:0)

<强>被修改 基于Vittorio Romeo的评论,更新为传递向量作为const引用,并在 linea 抛物线 API中添加必要的断言。

如果你想避免可变参数函数,这是一种天真的方法。由于您的功能界面已明确定义,您可以在 linea 抛物线函数中传递double类型参数的矢量或数组。

#include <vector>

using namespace std;

double linea(const std::vector<double>& params)
{
    assert(params.size() == 3 /*Linear 3 parameters required*/);
    return params[0] * params[1] + params[2];
}

double parabola(const std::vector<double>& params)
{
    assert(params.size() == 4 /*Parabola 4 parameters required*/);
    return params[0] * params[3] * params[3] +
        params[1] * params[3] +
        params[2];
}

konjgrad 函数的一点修改版本,它现在通过函数指针从底层调用返回double值。请注意,第一个参数清楚地定义了功能界面。第二个参数是双精度矢量。

double konjgrad(double(*function)(const std::vector<double>&), const std::vector<double>& params)
{
    return function(params);//returning value from here
}

最后,您应该如何调用上面定义的API。

int main(int argc, wchar_t* argv[])
{
    std::vector<double> vals;
    vals.push_back(1.6);
    vals.push_back(5.1);
    vals.push_back(2.6);
    double v1 = konjgrad(linea, vals);

    std::vector<double> parab;
    parab.push_back(2.4);
    parab.push_back(3.1);
    parab.push_back(4.0);
    parab.push_back(2.6);

    double v2 = konjgrad(parabola, parab);

    return 0;

}

希望这会有所帮助。