// Example program
#include <iostream>
#include <string>
#include <tuple>
#include <functional>
template<typename... Fn>
class LinearCombination {
public:
template<typename... Un>
LinearCombination(Un&&... fs)
: functions(std::forward<Un>(fs)...)
{
coefs.fill(0.0);
}
double operator()(double x) const
{
return evaluateImpl(x, std::integral_constant<size_t, sizeof...(Fn) - 1>());
}
void setCoef(size_t i, double c)
{
coefs[i] = c;
}
private:
template<size_t I>
double evaluateImpl(double x, std::integral_constant<size_t, I> index) const
{
return evaluateOne(x, index) + evaluateImpl<I - 1>(x, std::integral_constant<size_t, I - 1>());
}
template<size_t I>
double evaluateImpl(double x, std::integral_constant<size_t, 0> index) const
{
return evaluateOne(x, index);
}
template<size_t I>
double evaluateOne(double x, std::integral_constant<size_t, I>) const
{
auto coef = coefs[I];
return coef == 0.0 ? 0.0 : coef * std::get<I>(functions)(x);
}
std::tuple<Fn...> functions;
std::array<double, sizeof...(Fn)> coefs;
};
template<typename... Fn>
auto make_linear_combination(Fn&&... fn)
{
return LinearCombination<Fn...>{std::forward<Fn>(fn)...};
}
double A(double)
{
return 1.0;
}
/// Integration 1.0
double integrate3D(double (*f)(double, double, double))
{
return f(1, 2, 3);
}
struct YHelper {
static double Y(double x, double y, double z)
{
return (f(x+y) - f(x)) * (f(y+z) - f(y)) * A(z+y);
}
static std::function<double(double)> f;
};
std::function<double(double)> YHelper::f;
/// Integration 2.0
template<typename Integrable>
double integrate3D_2(Integrable&& f)
{
return f(1, 2, 3);
}
int main()
{
auto f1 = [](double x) { return x; };
auto f2 = [](double x) { return 2 *x; };
auto lc = make_linear_combination(std::move(f1), std::move(f2));
lc.setCoef(0, 1.0);
lc.setCoef(1, -1.0);
std::cout << lc(2.0) << "\n";
YHelper::f = std::ref(lc);
std::cout << integrate3D(&YHelper::Y) << "\n";
auto Y = [&lc](double x, double y, double z) { return (lc(x+y) - lc(x)) * (lc(y+z) - lc(y)) * A(z+y); };
std::cout << integrate3D_2(Y) << "\n";
}
Ly8gRXhhbXBsZSBwcm9ncmFtCiNpbmNsdWRlIDxpb3N0cmVhbT4KI2luY2x1ZGUgPHN0cmluZz4KCiNpbmNsdWRlIDx0dXBsZT4KI2luY2x1ZGUgPGZ1bmN0aW9uYWw+Cgp0ZW1wbGF0ZTx0eXBlbmFtZS4uLiBGbj4KY2xhc3MgTGluZWFyQ29tYmluYXRpb24gewpwdWJsaWM6CiAgICB0ZW1wbGF0ZTx0eXBlbmFtZS4uLiBVbj4KICAgIExpbmVhckNvbWJpbmF0aW9uKFVuJiYuLi4gZnMpCiAgICA6IGZ1bmN0aW9ucyhzdGQ6OmZvcndhcmQ8VW4+KGZzKS4uLikKICAgIHsKICAgICAgICBjb2Vmcy5maWxsKDAuMCk7CiAgICB9CiAgICAKICAgIGRvdWJsZSBvcGVyYXRvcigpKGRvdWJsZSB4KSBjb25zdCAKICAgIHsKICAgICAgICByZXR1cm4gZXZhbHVhdGVJbXBsKHgsIHN0ZDo6aW50ZWdyYWxfY29uc3RhbnQ8c2l6ZV90LCBzaXplb2YuLi4oRm4pIC0gMT4oKSk7CiAgICB9CiAgICAKICAgIHZvaWQgc2V0Q29lZihzaXplX3QgaSwgZG91YmxlIGMpCiAgICB7CiAgICAgICAgY29lZnNbaV0gPSBjOwogICAgfQogICAgCnByaXZhdGU6CiAgICB0ZW1wbGF0ZTxzaXplX3QgST4KICAgIGRvdWJsZSBldmFsdWF0ZUltcGwoZG91YmxlIHgsIHN0ZDo6aW50ZWdyYWxfY29uc3RhbnQ8c2l6ZV90LCBJPiBpbmRleCkgY29uc3QKICAgIHsKICAgICAgICByZXR1cm4gZXZhbHVhdGVPbmUoeCwgaW5kZXgpICsgZXZhbHVhdGVJbXBsPEkgLSAxPih4LCBzdGQ6OmludGVncmFsX2NvbnN0YW50PHNpemVfdCwgSSAtIDE+KCkpOwogICAgfQogICAgCiAgICB0ZW1wbGF0ZTxzaXplX3QgST4KICAgIGRvdWJsZSBldmFsdWF0ZUltcGwoZG91YmxlIHgsIHN0ZDo6aW50ZWdyYWxfY29uc3RhbnQ8c2l6ZV90LCAwPiBpbmRleCkgY29uc3QKICAgIHsKICAgICAgICByZXR1cm4gZXZhbHVhdGVPbmUoeCwgaW5kZXgpOwogICAgfQoKICAgIHRlbXBsYXRlPHNpemVfdCBJPgogICAgZG91YmxlIGV2YWx1YXRlT25lKGRvdWJsZSB4LCBzdGQ6OmludGVncmFsX2NvbnN0YW50PHNpemVfdCwgST4pIGNvbnN0CiAgICB7CiAgICAgICAgYXV0byBjb2VmID0gY29lZnNbSV07CiAgICAgICAgcmV0dXJuIGNvZWYgPT0gMC4wID8gMC4wIDogY29lZiAqIHN0ZDo6Z2V0PEk+KGZ1bmN0aW9ucykoeCk7CiAgICB9CiAgICAKCiAgICBzdGQ6OnR1cGxlPEZuLi4uPiBmdW5jdGlvbnM7CiAgICBzdGQ6OmFycmF5PGRvdWJsZSwgc2l6ZW9mLi4uKEZuKT4gY29lZnM7Cn07Cgp0ZW1wbGF0ZTx0eXBlbmFtZS4uLiBGbj4KYXV0byBtYWtlX2xpbmVhcl9jb21iaW5hdGlvbihGbiYmLi4uIGZuKQp7CiAgICByZXR1cm4gTGluZWFyQ29tYmluYXRpb248Rm4uLi4+e3N0ZDo6Zm9yd2FyZDxGbj4oZm4pLi4ufTsKfQoKZG91YmxlIEEoZG91YmxlKSAKewogICAgcmV0dXJuIDEuMDsKfQoKLy8vIEludGVncmF0aW9uIDEuMApkb3VibGUgaW50ZWdyYXRlM0QoZG91YmxlICgqZikoZG91YmxlLCBkb3VibGUsIGRvdWJsZSkpCnsKICAgIHJldHVybiBmKDEsIDIsIDMpOwp9CgpzdHJ1Y3QgWUhlbHBlciB7CiAgICBzdGF0aWMgZG91YmxlIFkoZG91YmxlIHgsIGRvdWJsZSB5LCBkb3VibGUgeikKICAgIHsKICAgICAgICByZXR1cm4gKGYoeCt5KSAtIGYoeCkpICogKGYoeSt6KSAtIGYoeSkpICogQSh6K3kpOwogICAgfQogICAgCiAgICBzdGF0aWMgc3RkOjpmdW5jdGlvbjxkb3VibGUoZG91YmxlKT4gZjsKfTsKCnN0ZDo6ZnVuY3Rpb248ZG91YmxlKGRvdWJsZSk+IFlIZWxwZXI6OmY7CgoKLy8vIEludGVncmF0aW9uIDIuMAp0ZW1wbGF0ZTx0eXBlbmFtZSBJbnRlZ3JhYmxlPgpkb3VibGUgaW50ZWdyYXRlM0RfMihJbnRlZ3JhYmxlJiYgZikKewogICAgcmV0dXJuIGYoMSwgMiwgMyk7Cn0KCmludCBtYWluKCkKewogICAgYXV0byBmMSA9IFtdKGRvdWJsZSB4KSB7IHJldHVybiB4OyB9OwogICAgYXV0byBmMiA9IFtdKGRvdWJsZSB4KSB7IHJldHVybiAyICp4OyB9OwogICAgCiAgICBhdXRvIGxjID0gbWFrZV9saW5lYXJfY29tYmluYXRpb24oc3RkOjptb3ZlKGYxKSwgc3RkOjptb3ZlKGYyKSk7CiAgICBsYy5zZXRDb2VmKDAsIDEuMCk7CiAgICBsYy5zZXRDb2VmKDEsIC0xLjApOwogICAgCiAgICBzdGQ6OmNvdXQgPDwgbGMoMi4wKSA8PCAiXG4iOwoKICAgIFlIZWxwZXI6OmYgPSBzdGQ6OnJlZihsYyk7CiAgICBzdGQ6OmNvdXQgPDwgaW50ZWdyYXRlM0QoJllIZWxwZXI6OlkpIDw8ICJcbiI7CgogICAgYXV0byBZID0gWyZsY10oZG91YmxlIHgsIGRvdWJsZSB5LCBkb3VibGUgeikgeyByZXR1cm4gKGxjKHgreSkgLSBsYyh4KSkgKiAobGMoeSt6KSAtIGxjKHkpKSAqIEEoeit5KTsgfTsKICAgIHN0ZDo6Y291dCA8PCBpbnRlZ3JhdGUzRF8yKFkpIDw8ICJcbiI7Cn0K