从另一个函数创建一个函数
Create a function from another one
不仅仅是一般情况,我有一个非常具体的例子:在GSL (GNU科学库)中,使用的主要函数类型(为了执行积分,根查找,…)是gsl_function
,它有一个属性function
,其类型是double(*)(double, void *)
假设我想从double a_squared(double a) {return a*a};
创建一个gsl_function
。a__squared
的类型是double(*)(double)
我想创建一个convert
函数,接受参数(double(*)(double) f)
并返回一个类型为double(*)(double, void *)
的对象,该对象将满足convert(f)(double a, NULL) == f(a)
但是经过一些研究,似乎我不能在我的convert
函数中定义另一个函数。
将原始函数指针传递给GSL API的需要极大地限制了您的选择-您不能使用基于std::function
的任何东西,因为没有办法从std::function
获得函数指针(这排除了使用捕获的lambda,这将提供一个整洁的解决方案)。
考虑到这些约束,这里有一个使用静态包装器类的可能解决方案。您也可以将该类的内容放在名称空间中,但使用该类至少可以提供一些封装的外观。
typedef double gsl_function_type(double, void*); // typedef to make things a bit more readable...
// static class to wrap single-parameter function in GSL-compatible interface
// this really just serves as a namespace - there are no non-static members,
// but using a class lets us keep the details private
class Convert
{
Convert() = delete; // don't allow construction of this class
// pointer to the function to be invoked
static double (*m_target)(double);
// this is the function we'll actually pass to GSL - it has the required signature
static double target(double x, void*) {
return m_target(x); // invoke the currently wrapped function
}
public:
// here's your "convert" function
static gsl_function_type* convert(double (*fn)(double)) {
m_target = fn;
return ⌖
}
};
这里有一个活生生的例子:http://coliru.stacked-crooked.com/a/8accb5db47a0c51d
您被gsl(糟糕的)设计选择所困,使用C(而不是c++)来提供C风格的函数指针。因此,您不能使用(c++风格)函数对象(functor),而必须提供指向实际函数的指针,并且不能以生成functor的相同方式生成函数。
(不推荐)您可以使用一个全局变量来存储实际的函数(a_squared
),然后定义一个实际调用该全局变量的特定gsl_function
:
// from some gsl header:
extern "C" {
typedef double gsl_function(double, void*);
// calls func(arg,data_passed_to_func)
double gsl_api_function(gsl_function*func, void*data_passed_to_func);
}
// in your source code
double(*target_func)(double); // global variable can be hidden in some namespace
extern "C" {
double funtion_calling_target(double, void*)
}
double funtion_calling_target(double arg, void*)
{
return target_func(arg);
}
bool test(double x, double(*func)(double))
{
target_func = func;
return x < gsl_api_function(function_calling_target,0);
}
(隐藏target_func
作为某个类的静态成员,如在atkins的回答中仍然需要一个全局变量)。这是有效的,但是很差,因为1)这种机制需要一个全局变量,2)只允许在任何时候使用一个目标函数(这可能很难确保)。
(推荐)但是,您可以定义一个特殊的函数,该函数将另一个函数指针作为参数并将其作为数据元素传递。这实际上是gsl_function
设计背后的思想:void*
可以指向函数可能需要的任何辅助数据。这些数据可以是另一个函数。
// your header
extern "C" {
double function_of_double(double, void*);
}
inline double function_of_double(double arg, void*func)
{
typedef double(*func_of_double)(double);
return reinterpret_cast<func_of_double>(func)(arg);
}
// your application
bool test(double x, double(*func)(double))
{
return x < gsl_api_function(function_of_double, (void*)(func));
}
这不需要全局变量,并且可以根据需要同时使用许多不同的函数。当然,这里你是在乱搞void*
,这是每个理智的c++程序员都讨厌的东西,但你使用的是一个基于void*
操作的可怕的C库。
我想我会在这里添加基于lambda的尝试。
它在原则上工作得很好:
// function we want to pass to GSL
double a_squared(double a) { return a*a; }
typedef double gsl_function_type(double, void*); // convenient typedef
// lambda wrapping a_squared in the required interface: we can pass f directly to GSL
gsl_function_type* f = [](double x, void*) { return a_squared(x); };
但我们真的想写一个方法来应用到任何给定的函数。像这样:
gsl_function_type* convert(double (*fn)(double))
{
// The lambda has to capture the function pointer, fn.
return [fn](double x, void*) { return fn(x); };
}
然而,lambda现在必须捕获指针fn
,因为fn
具有自动存储持续时间(与第一个示例中的静态函数a_squared
相反)。这不能编译,因为使用捕获的lambda不能按照函数返回值的要求转换为简单的函数指针。为了能够返回这个lambda,我们必须使用std::function
,但是没有办法从中获得原始函数指针,所以这里没有用。
所以我已经设法得到这个工作的唯一方法是通过使用预处理宏:
#define convert(f) [](double x, void*) { return f(x); }
然后让我这样写:
#include <iostream>
using namespace std;
typedef double gsl_function_type(double, void*); // convenient typedef
// example GSL function call
double some_gsl_function(gsl_function_type* function)
{
return function(5.0, nullptr);
}
// function we want to pass to GSL
double a_squared(double a) { return a*a; }
// macro to define an inline lambda wrapping f(double) in GSL signature
#define convert(f) [](double x, void*) { return f(x); }
int main()
{
cout << some_gsl_function(convert(a_squared)) << endl;
}
就我个人而言,尽管我不喜欢使用宏,但我更喜欢这个。特别是,它解决了@Walter在那个想法中指出的问题。
前面的答案—包括被接受的答案—似乎是正确的,但是如果您需要将其他类型的函数转换为gsl_function(例如包括成员函数),它们就不够通用。所以,让我添加一个更强大的选项。
如果您使用这里描述的包装器,那么您可以通过两行简单的代码将任何c++ lambdas转换为gsl_functions
// Example
gsl_function_pp Fp([&](double x){return a_squared(x);});
gsl_function *F = static_cast<gsl_function*>(&Fp);
这解决了任何相关的转换问题。你也可以使用std::bind和任何std::函数。
- 函数向量_指针有不同的原型,我可以构建一个吗
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何仅为一个函数添加延迟
- 构造函数正在调用一个使用当前类类型的函数
- C++-试图将函数指针推回到另一个CPP文件中的矢量时出错
- 有一个打印语句的函数是一种糟糕的编程实践吗
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 输入到文件并输出到另一个文件,并将流文件传递给函数
- 我不明白为什么我声明一个空的内部结构并将其传递给构造函数
- 如何创建函数管道,以便函数一个接一个地运行?
- 如何巧妙地编写两个函数——一个用于检查是否存在解决方案,另一个用于获取所有解决方案
- 在c++中的复制构造函数/一个声明语句中的初始化的延续中使用chain方法
- C :基类调用自己的虚拟函数 - 一个反图案
- 如何在这个交换函数(一个单独的链表)中找到错误
- 两个相同的函数(一个使用模板模式,另一个不使用)
- 你怎么能一次给一个函数一个参数呢
- 为什么要做两个函数?(一个是非const,另一个是const)
- 当代码在其他地方使用时,如何保证函数一个接一个地被调用