[英]Passing a math function as method's input parameter C++
I am trying to write a general integral function and I would like to implement it in such a way so that it can accept any mathematical function. 我正在尝试编写一个通用的积分函数,我想以这样的方式实现它,以便它可以接受任何数学函数。 That is, I would like to pass the math function as an input parameter.
也就是说,我想将数学函数作为输入参数传递。 In pseudo-code:
simpson_int(x*x)
. 在伪代码中:
simpson_int(x*x)
。 I've heard of the function
template in <functional>
but I don't really have experience with templates in C++. 我听说过
<functional>
中的function
模板,但我并不熟悉C ++中的模板。
There are some solutions that comes in my mind (and this is my approach at the problem, for sure there are more solution, and maybe what I'm pointing out is not the best), that consider the fact that you need to call the argument function more than once in the Simpson implementation (thus you need a "callable" argument ): 我脑子里有一些解决方案(这是我解决问题的方法,肯定有更多解决方案,也许我指出的不是最好的),考虑到你需要调用在Simpson实现中不止一次参数函数(因此你需要一个“可调用的”参数 ):
Function pointers (more C than C++), where you declare with two arguments: the first one will be the pointer to a function with the specified types, while the second is the argument for your function. 函数指针(比C ++更多),用两个参数声明:第一个是指向具有指定类型的函数的指针,而第二个是函数的参数。 Lets make an example:
让我们举一个例子:
#include <iostream>
double power2(double x) {
return x * x;
}
double simspon(double (*f)(double), double x) {
return f(x);
}
int main() {
std::cout << simspon(power2, 2);
return 0;
}
In this case I have used no templates for reaching the result. 在这种情况下,我没有使用模板来达到结果。 But this will not take any function as first argument, but only a function that has as argument a double and returns a double.
但是这不会将任何函数作为第一个参数,而只是一个函数,其参数为double并返回double。
I think that most of c++ programmer will suggest you to avoid this method. 我认为大多数c ++程序员会建议你避免使用这种方法。
So you maybe want to expand the previous example using templates and making it more general. 因此,您可能希望使用模板扩展前面的示例并使其更加通用。 It is quite simple to redefine the function to accept a template (an abstract type) that you actually specify only when you use it in your code:
重新定义函数以接受仅在代码中使用时实际指定的模板(抽象类型)非常简单:
#include <iostream>
double power2(double x) {
return x * x;
}
int power2int(int x) {
return x * x;
}
template <class T, class P>
P simspon(T (*f)(P), P x) {
return f(x);
}
int main() {
std::cout << simspon<double, double>(power2, 2.0);
std::cout << simspon<int, int>(power2int, 2);
return 0;
}
T
and P
are two templates: the first one is used for describing the returned value of the function pointer, while the second specify the argument of the function pointer, and the returned value of simpson
.So when you are writing template <class T, classP>
you are actually informing the compiler that that you are using T and P as placeholder for different type. T
和P
是两个模板:第一个用于描述函数指针的返回值,第二个用于指定函数指针的参数,以及simpson
.So的返回值,当您编写template <class T, classP>
实际上,您正在通知编译器您正在使用T和P作为不同类型的占位符。 You will actually declare the type that you want later on, when you will call the function in the main
. 实际上,当您将在
main
调用该函数时,您将实际声明您想要的类型。 This is not good code but I'm building the path to understand templates. 这不是好代码,但我正在构建理解模板的路径。 Also, you specify the type of your argument function when you actually call
simpson
, with the < >
. 另外,在实际调用
simpson
,使用< >
指定参数函数的类型 。
( Disclaimer: you should consider to use template <typename T ...>
instead of class. But I'm used with the old class
and there are situation in which typename
cannot be used, there are a lot of questions on SO that dive into this.) ( 免责声明:您应该考虑使用
template <typename T ...>
而不是类,但我与老使用。 class
和有情况,即typename
不能用,有很多的问题上,这样的潜水进入这个。)
std::function
std::function
Instead of using a function pointer as argument you may want to create a variable that stores your function to be passed as argument of simpson
. 您可能希望创建一个变量来存储您要作为
simpson
参数传递的函数,而不是使用函数指针作为参数。 This bring several advantages, because they are actually an object inside your code that have some predictable behavior in some unwanted circumstances (for example, in case of a null function pointer you have to check the pointer itself and handle it, in case of std::function
if there is no callable pointer it throws std::bad_function_call
error) 这带来了几个优点,因为它们实际上是代码中的一个对象,在某些不需要的情况下具有一些可预测的行为(例如,在null函数指针的情况下,你必须检查指针本身并处理它,如果是
std::function
如果没有可调用指针则抛出std::bad_function_call
错误)
Here an example, and it uses again templates, as before: 这是一个例子,它再次使用模板,如前所述:
#include <iostream>
#include <functional>
double power2(double x) {
return x * x;
}
int power2int(int x) {
return x * x;
}
template <class T, class P>
P simspon(std::function<T(P)> f, P x) {
return f(x);
}
int main() {
std::function<double(double)> p_power2 = power2;
std::cout << simspon<double, double>(p_power2, 2.0);
std::function<double(double)> p_power2int = power2int;
std::cout << simspon<int, int>(power2int, 2);
return 0;
}
lambdas are closure and in your case (if you can use the standard C++14) can be used alongside the auto
keyword to achieve quite a general behavior, without the explicit use of templates. lambda是闭包的,在你的情况下(如果你可以使用标准的C ++ 14)可以与
auto
关键字一起使用,以实现相当普遍的行为,而无需明确使用模板。 The closure are also able to capture part/the whole context, check the reference for this. 闭包还能够捕获部分/整个上下文, 检查参考 。
Let's see an example, in which I create two lambdas that receive different arguments and a simpson
function that is quite general (actually it is not, is the compiler that defines different functions with respect to the call that you do). 让我们看一个例子,其中我创建两个接收不同参数的lambda和一个非常通用的
simpson
函数(实际上它不是,编译器定义了与你所做的调用相关的不同函数)。
#include <iostream>
auto lambda = [](auto x) { return x * x ; };
auto lambda_2 = [] (int x) { return x + 10; };
auto simpson(auto f, auto x) {
return f(x);
}
int main() {
std::cout << simpson(lambda, 2.0);
std::cout << simpson(lambda_2, 1);
return 0;
}
You need to compile it with the -std=c++14
flag. 您需要使用
-std=c++14
标志进行编译。 There are tons of advise that comes in my mind to suggest you to avoid to implement your code in this way, remember that it has only some illustrative purposes (I've more than exaggerated with the auto
keyword). 我想到了很多建议,建议你避免以这种方式实现你的代码,请记住它只有一些说明性的目的(我不仅仅夸大了
auto
关键字)。
Maybe an improvement for your case is to write a general class for the mathematical functions to integrate and pass the object to your function. 也许对你的情况进行改进的是为数学函数编写一个通用类来集成并将对象传递给你的函数。 This bring several advantages: you may want to save some of the integrative result inside your function or even write the stream operator to pretty print your problem.
这带来了几个优点:您可能希望在函数中保存一些综合结果,甚至可以编写流操作符来打印您的问题。 This is the solution employed typically by mathematical libraries.
这是数学图书馆通常采用的解决方案。
In this extremely simple case, we have a class that is a problem. 在这个非常简单的情况下,我们有一个问题的类。 When you create a new instance for this class, a
std::function
is passed to the constructor and stored inside the class. 为此类创建新实例时,
std::function
将传递给构造函数并存储在类中。 The instance of the class is the argument for your simpson
: 类的实例是你的
simpson
的参数:
#include <iostream>
#include <functional>
template <class T, class P>
class Problem {
public:
// Attributes
std::function<T(P)> _f;
// Constructor
Problem(std::function<T(P)> f) : _f(f) {};
// Making the object callable
P operator()(P x) { return _f(x); }
};
template <class T, class P>
P simspon(Problem<T, P> p, P x) {
return p(x);
}
int main() {
Problem<double, double> prb([](double x) { return x * x; });
std::cout << simspon<double, double>(prb, 2);
return 0;
}
Use std::function
, like this for example: 使用
std::function
,例如:
#include <iostream> // std::cout
#include <functional> // std::function
int main()
{
std::function<double(double)> simpson_int =([](double x) { return x * x; };
std::cout << "simpson_int(4): " << simpson_int(4) << '\n';
return 0;
}
which outputs: 哪个输出:
simpson_int(4): 16
simpson_int(4):16
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.