如何在C++中使用单个模板参数传递两个 lambda 函数
How to pass two lambda functions using a single template parameter in C++
我正在编写一个程序,以数字方式计算voigt分布的值。但是,当我尝试使用单个类模板参数传递高斯和洛仑兹函数时,我遇到了一个问题F
,即使它们是同一类型。
当我使用两个模板参数时,比如F1
和F2
,它就像一个魅力。但是只要只有一个错误,g++ 就会抛出一个错误。将 lambda 立即作为splot
的(卷积)参数传递是没有帮助的。
#define _USE_MATH_DEFINES
#include <iostream>
#include <cmath>
#include <functional>
using namespace std;
#define MIN -10.
#define MAX 10.
#define EPS 0.01
template <typename T, class F> T trapezoid(F f, T a, T b, T eps) {
T result = T(0);
while (a <= b) {
result += f(a);
a += eps;
}
result -= (f(a) + f(b)) / T(2);
return result * eps;
}
template <class F>
double splot(F g, F l, double x, double sigma, double gamma) {
auto s = [g, l, x, sigma, gamma](double x_prime)->double {
return g(x_prime, sigma) * l(x - x_prime, gamma);
};
return trapezoid(s, MIN, MAX, EPS);
}
int main (void) {
double x = 0., sigma = 1.5, gamma = 0.1;
auto gauss = [](double x, double sigma)->double {
return exp(-1*x*x / (2*sigma*sigma)) / (sigma * sqrt(2*M_PI));
};
auto lorentz = [](double x, double gamma)->double {
return gamma / (M_PI*(x*x + gamma*gamma));
};
cout << "x: " << x << endl << "V(x): " <<
splot(gauss, lorentz, x, sigma, gamma) << endl;
return 0;
}
我建议您使用如下所示的std::function<>
:
typedef std::function<double(double,double)> func;
func gauss = [](double x, double sigma)->double {
return exp(-1*x*x / (2*sigma*sigma)) / (sigma * sqrt(2*M_PI));
};
func lorentz = [](double x, double gamma)->double {
return gamma / (M_PI*(x*x + gamma*gamma));
};
cout << "x: " << x << endl << "V(x): " <<
splot(gauss, lorentz, x, sigma, gamma) << endl;`
正如@Christophe指出的那样,lambda 将具有不同的类型,而另一方面,这可以确保您为所有方法保持相同的类型。
有什么问题?
如果我很好地理解您的问题,当您定义splot()
时,对传递的每个 lambda 使用不同的模板参数,它可以完美编译:
template <class F1, class F2>
double splot(F1 g, F2 l, double x, double sigma, double gamma) {
...
}
但是您使用的两个 lambda 具有相同的签名(相同的参数类型和相同的返回类型),因此您希望它们属于相同的类型,并且还需要编译以下splot()
定义:
template <class F>
double splot(F g, F l, double x, double sigma, double gamma) {
...
}
但是它不能编译,编译器甚至会混淆一条错误消息,该错误消息表明两个 lambda 具有不同的类型,而显示的类型名称指示相同的类型:
note: template argument deduction/substitution failed:
note: deduced conflicting types for parameter ‘F’ (‘main()::<lambda(double, double)>’ and ‘main()::<lambda(double, double)>’)
为什么会有问题?
尽管存在误导性的错误消息,编译器是正确的。F
的类型推导中存在错误:C++标准在[expr.prim.lambda.closure]/1
中指出:
lambda 表达式的类型(也是闭包的类型) object)是唯一的、未命名的非联合类类型,称为闭包 类型,其属性如下所述。
因此,每个 lambda 都有不同的类型,即使它们共享相同的签名。
这基本上是因为它们不属于同一类型。
#include <iostream>
#include <cmath>
using namespace std;
int main (void) {
auto gauss = [](double x, double sigma)->double {
return exp(-1*x*x / (2*sigma*sigma)) / (sigma * sqrt(2*M_PI));
};
auto lorentz = [](double x, double gamma)->double {
return gamma / (M_PI*(x*x + gamma*gamma));
};
cout << typeid(gauss).name() << endl;
cout << typeid(lorentz).name() << endl;
return 0;
}
看看它如何为每个函数提供不同的 ID。在此链接中几乎没有解释。然后我想你必须坚持做:
template <class F, class G>
double splot(F g, G l, double x, double sigma, double gamma) {
auto s = [g, l, x, sigma, gamma](double x_prime)->double {
return g(x_prime, sigma) * l(x - x_prime, gamma);
};
return trapezoid(s, MIN, MAX, EPS);
}
或者你应该像Compare
一样制作模板,或者使用类binary_function
。请参阅示例。
原因是每个 lambda 都是它自己的、不同的类型,并且您的函数splot()
要求g
和l
是完全相同的类型。如果您将相同的 lambda 传递给splot()
,您会注意到它会编译正常:
cout << "x: " << x << endl << "V(x): " <<
splot(gauss, gauss, x, sigma, gamma) << endl;
但是你需要模板吗?您只需要确保前两个参数是所需类型的函数,并且您已经知道该类型,因此请尝试以下操作:
double splot(std::function<double(double, double)> g, std::function<double(double, double)> l, double x, double sigma, double gamma) {
...
}
- 如何巧妙地编写两个函数——一个用于检查是否存在解决方案,另一个用于获取所有解决方案
- 两个函数模板候选项.将一个参数作为引用后,选择不太专业的模板
- 如何比较两个函数的速度和性能
- 如何在构造器的成员初始值设定项列表中调用两个函数?
- 如何将这两个函数组合成一个实现?
- 将具有相反操作数的两个函数重构为一个
- 创建整数的 2D 数组,该数组将使用两个函数用随机数填充矩阵.我做错了什么?
- 具有相同主体的两个函数具有不同的名称
- 通过作为类的公共成员的两个函数将函数作为参数传递
- 如何使用排序和比较这两个函数在 c++ 中对字符数组进行排序?
- 是否可以在C++中将两个函数一起添加
- C++ 两个函数除了一行之外执行相同的操作
- 如何编写连接两个函数的函数
- 如何执行两个函数参数具有相同的模板类型
- 当两个函数位于一行中时,堆栈框架的样子
- 为什么这两个函数的行为不同
- 为什么当我有两个函数时编译器没有显示错误,一个将采用基类,一个将派生类作为参数
- 系统堆栈中的两个函数的递归调用(将不同数量的数组作为参数传递)有什么区别
- 如何在一个构造函数中使用两个可变参数模板参数来绑定两个函数
- 如何在c++中的两个函数中传递对象的同一实例