Passing a math function as method's input parameter C++ - 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). I've heard of the function template in <functional> but I don't really have experience with templates in 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):
Function pointer
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. 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.
I think that most of c++ programmer will suggest you to avoid this method.
Function pointer and templates
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. You will actually declare the type that you want later on, when you will call the function in the 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 < >.
(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.)
Using 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. 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)
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;
}
Using lambdas
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. 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).
#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. 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).
Function objects (the Problem class)
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. The instance of the class is the argument for your 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:
#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

Related

Is there any reason to wrap a Lambda in a named function?

I recently stumbled upon this example code and I was confused:
auto named_funct(const MyClass& some_class)
{
return [some_class](const MyClass2& some_other_class)
{
return some_class <= some_other_class; // some expression between capture and input parameter to the Lambda
};
}
Is there any reason at all to wrap an anonymous function in a named function? It seems like an extra function call stack is being created for no reason.
named_funct doesn't execute the lambda, it returns it. You could use it like this:
auto it = std::find_if(std::begin(some_vector), std::end(some_vector),
named_funct(some_instance));
The odd thing is that named_funct takes a parameter that it doesn't do anything with, unless you have a copy/paste error (another instance is passed to the actual lambda). This example is also so trivial I don't see the benefit of a lambda, but if named_funct's argument was captured and used somehow, this is a useful pattern.
There can be a reason (if, for example, you want partial functions (the ability to do f(x)(y) rather than f(x, y))), but there isn't here. The outer input argument is shadowed by the argument of the anonymous function.
To add another possible (slightly modified) use case for this pattern:
you could return different implementations of the lambda even with different return types based on templated traits like in following example
#include <iostream>
#include <string>
enum class MyTrait
{
Default,
Other
};
struct Foo
{
std::string Baz() const { return "bar"; };
int Bazz() const { return 42; };
};
template <MyTrait>
struct LambdaGenerator;
template <>
struct LambdaGenerator<MyTrait::Default>
{
auto operator()(const Foo& foo) const { return [&]{ return foo.Baz(); }; }
};
template <>
struct LambdaGenerator<MyTrait::Other>
{
auto operator()(const Foo& foo) const { return [&]{ return foo.Bazz(); }; }
};
int main()
{
std::cout << LambdaGenerator<MyTrait::Default>()(Foo())() << std::endl;
std::cout << LambdaGenerator<MyTrait::Other>()(Foo())() << std::endl;
// prints
// bar
// 42
}
I quite often used this when working with C++ AMP to implement different variants of GPU targeted algorithms (which in AMP are lambda objects).

compile error about template deduction on c++

#include <iostream>
template <int N>
class X {
public:
using I = int;
void f(I i) {
std::cout << "i: " << i << std::endl;
}
};
template <int N>
void fppm(void (X<N>::*p)(typename X<N>::I)) {
p(0);
}
int main() {
fppm(&X<33>::f);
return 0;
}
I just don't understand the compile error message of the code.
error: called object type 'void (X<33>::*)(typename X<33>::I)' is not a function or function pointer
p(0);
I think p is a function which returns void and takes int as its argument. But apparently, it's not. Could somebody give me clue?
Since p is a pointer to a nonstatic member function, you need an instance to call it with. Thus, first instantiate an object of X<33> in main:
int main() {
X<33> x;
fppm(x, &X<33>::f); // <-- Signature changed below to accept an instance
Then in your function, change the code to accept an instance of X<N> and call the member function for it:
template <int N>
void fppm(X<N> instance, void (X<N>::*p)(typename X<N>::I)) {
(instance.*p)(0);
}
The syntax may look ugly but the low precedence of the pointer to member operator requires the need for the parentheses.
As denoted in the comments already, p is a pointer to member function, but you call it like a static function (p(0);). You need a concrete object to call p on:
X<N> x;
(x.*p)(0);
// or:
X<N>* xx = new X<N>();
(xx->*p)(0);
delete xx;
Be aware that the .*/->* operators have lower precedence than the function call operator, thus you need the parentheses.
Side note: Above is for better illustration, modern C++ might use auto keyword and smart pointers instead, which could look like this:
auto x = std::make_unique<X<N>>();
(x.get()->*p)(0);

Bind utility and templated functions

It follows a minimal example of the bind function in use.
It compiles and it is pretty trivial an example indeed.
#include <functional>
void fn(int i) { }
int main() {
int x = 0;
auto f = std::bind(fn, x);
}
I would be interested in doing the same with a templated function.
It follows the example above, even though slightly modified. This one doesn't compile, but it explains exactly which is the intended behavior.
#include <functional>
template<typename T>
void fn(T t) { }
int main() {
int x = 0;
auto f = std::bind(fn, x);
}
Quite simple a question: is it possible to use bind utility with a templated function?
I think the obvious solution is the code below.
#include <functional>
template<typename T>
void fn(T t) { }
int main() {
int x = 0;
auto f = std::bind(fn<int>, x);
}
If you don't want to be specific about the instantiation, maybe you can add one more template level. I'm making some tests.
EDIT: I spent a few hours thinking by myself, googling around and reading my printed TC++PL4Ed, as well as reading the implementation of GNU's libstdc++ source code, and I didn't figure nor did I find out how to do what you asked.
It turns out that when you made fn the name of a template, it could no longer be used as the name of an object. Since std::bind deduces its return type from (the types of) its arguments, the use of just fn became invalid. To have a callable object that qualifies as first argument to std::bind, you must now instantiate the template fn.

Why can't decltype work with overloaded functions?

decltype fails if the function you're calling it on is overloaded, as in this code:
#include <iostream>
int test(double x, double y);
double test(int x, int y);
char test(char x, int y);
int main()
{
std::cout << decltype(test) << std::endl;
return 0;
}
Results:
error: decltype cannot resolve address of overloaded function
I understand that this is because decltype can't figure out which function you're trying to get the type of. But why isn't there another way to make this work, like this:
std::cout << decltype(test(double, double)) << std::endl;
or this:
double x = 5, y = 2;
std::cout << decltype(test(x, y)) << std::endl;
Since a function cannot be overloaded simply based on return type, wouldn't passing either datatypes or actual variables to the decltype call be enough to tell it which of the overloads it's supposed to examine? What am I missing here?
To figure out the type of the function from the type of the arguments you'd pass, you can "build" the return type by using decltype and "calling" it with those types, and then add on the parameter list to piece the entire type together.
template<typename... Ts>
using TestType = decltype(test(std::declval<Ts>()...))(Ts...);
Doing TestType<double, double> will result in the type int(double, double). You can find a full example here.
Alternatively, you might find the trailing return type syntax more readable:
template<typename... Ts>
using TestType = auto(Ts...) -> decltype(test(std::declval<Ts>()...));
I belive you may be looking for std::result_of<>
cppreference page.
I have found another way: use std::declval to generate a fake object, then use decltype:
#include <type_traits>
#include <functional>
int myfunc(int a)
{
return a;
}
float myfunc(float a)
{
return a;
}
int main()
{
decltype(myfunc(std::declval<float>())) a; // return type
std::function<decltype(a)(float)> fun; // function type
return 0;
}

Is mycomparison a object , function or function pointer?

I was going through following code:
template <typename String>
void test_decimals()
{
SensibleLessThan<String> mycomparison;
String lhs = "1.212";
String rhs = "1.234";
CHECK_EQUAL(mycomparison(lhs, rhs), true); // CHECK EQUAL is macro
}
I do not understand the meaning of the following constructs:
SensibleLessThan<String> mycomparison;
mycomparison(lhs, rhs)
Is mycomparison an object, a function or a function pointer?
SensibleLessThan<String> is a type. mycomparison is an object of that type. Now it appears that the type overloads operator(), which allows it to be called as though it were a function. Objects of such types are usually known as function objects or functors. Such objects are, like functions, considered callable.
For a simple example, here's an adder struct that overloads operator(). We can create an object of the adder type and then use that object as though it were a function.
#include <iostream>
struct adder
{
int operator()(int a, int b) { return a + b; }
};
int main()
{
adder my_adder;
std::cout << my_adder(5, 6) << std::endl;
}
Here it is in action. In fact, a similar type already exists in the C++ standard library: std::plus.