I am writing a program that calculates numerically the value of the voigt distribution. However I'm encountering a problem when I try to pass gauss' and lorentz's functions using a single class template parameter F
, even though they are of the same type.
When I use two templates arguments, say F1
and F2
, it works like a charm. But g++ throws an error whenever there is just one. Passing the lambdas immediately as splot
's (convolution's) parameters doesn't help.
#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;
}
If I understand well your question, when you define splot()
, using a different template parameter for each lambda passed, it compiles perfectly:
template <class F1, class F2>
double splot(F1 g, F2 l, double x, double sigma, double gamma) {
...
}
But both lambdas that you use have the same signature (same argument types and same return type) so you expect them to be of the same type, and the following definition of splot()
to compile as well:
template <class F>
double splot(F g, F l, double x, double sigma, double gamma) {
...
}
But it doesn't compile, and the compiler makes it even confusing with an error message that suggests that both lambdas have a different type, whereas the displayed type name indicates the same type:
note: template argument deduction/substitution failed:
note: deduced conflicting types for parameter ‘F’ (‘main()::<lambda(double, double)>’ and ‘main()::<lambda(double, double)>’)
The compiler is right despite the misleading error message. There is an error in the type deduction with F
: the C++ standard states in [expr.prim.lambda.closure]/1
that:
The type of a lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type, called the closure type, whose properties are described below.
So every lambda has a different type, even if they share the same signature.