我想到了一些解决方案(这是我解决问题的方法,当然还有更多解决方案,也许我指出的不是最好的),考虑到您需要的事实在 Simpson 实现中多次调用参数函数(因此您需要一个“可调用”参数):
函数指针
函数指针(C 多于 C++),在其中使用两个参数声明:第一个是指向具有指定类型的函数的指针,而第二个是函数的参数。让我们
举个例子:
#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;
}
在这种情况下,我没有使用任何模板来获得结果。但这将不会将任何函数作为第一个参数,而只会将一个以 double 作为参数并返回 double 的函数。
我认为大多数 c++ 程序员会建议你避免使用这种方法。
函数指针和模板
因此,您可能希望使用模板扩展前面的示例并使其更通用。重新定义函数非常简单
接受仅在代码中使用时才实际指定的模板(抽象类型):
#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和P是两个模板:第一个用于描述函数指针的返回值,第二个指定函数指针的参数,simpson的返回值。所以当您编写template <class T, classP> 时,您实际上是在通知编译器您正在使用 T 和 P 作为不同类型的占位符。稍后,当您将调用main 中的函数时,您实际上将声明您想要的类型。 这不是好的代码,但我正在构建理解模板的路径。此外,您在实际调用 simpson 时指定参数函数的类型,使用 < >。
(免责声明:你应该考虑使用template <typename T ...>而不是class。但是我用的是旧的class,有些情况typename不能用,有有很多关于 SO 的问题可以深入探讨。)
使用std::function
您可能希望创建一个变量来存储要作为simpson 的参数传递的函数,而不是使用函数指针作为参数。这带来了几个优点,因为它们实际上是代码中的一个对象,在某些不需要的情况下具有一些可预测的行为(例如,在空函数指针的情况下,您必须检查指针本身并处理它,以防@987654336 @如果没有可调用的指针,它会抛出std::bad_function_call错误)
这里是一个例子,它再次使用模板,和以前一样:
#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
lambdas 是闭包,在您的情况下(如果您可以使用标准 C++14)可以与 auto 关键字一起使用以实现相当普遍的行为,而无需显式使用模板。闭包还能够捕获部分/整个上下文,check the reference 为此。
让我们看一个示例,其中我创建了两个接收不同参数的 lambdas 和一个非常通用的 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;
}
您需要使用-std=c++14 标志编译它。我有很多建议建议您避免以这种方式实现代码,请记住它仅具有一些说明性目的(我用 auto 关键字夸大了)。
函数对象(问题类)
也许对您的情况的改进是为数学函数编写一个通用类,以集成并将对象传递给您的函数。这带来了几个优点:您可能希望将一些综合结果保存在您的函数中,或者甚至编写流运算符来漂亮地打印您的问题。这是数学库通常采用的解决方案。
在这个极其简单的例子中,我们有一个有问题的类。当您为此类创建新实例时,std::function 将传递给构造函数并存储在类中。该类的实例是您的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;
}