How to properly pass member function as a parameter - c++

How do I properly pass member function as a parameter?
MyCode:
#include <iostream>
using namespace std;
class Test
{
public:
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
typedef int (*funcPtr)(int a, int b);
int myFunc(funcPtr func, int a, int b)
{
return func(a, b);
}
void setup()
{
cout << myFunc(&Test::add, 5, 3) << endl;
cout << myFunc(&Test::sub, 5, 3) << endl;
}
};
int main()
{
Test test;
test.setup();
}
Result:
Error: Cannot initialize a parameter of type 'Test::funcPtr' (aka 'int
()(int, int)') with an rvalue of type 'int (Test::)(int, int)'
Expected Result:
8
2

Your methods should be "regular" functions. add static to them to allow to use them with function pointers:
class Test
{
public:
static int add(int a, int b)
{
return a + b;
}
static int sub(int a, int b)
{
return a - b;
}
// ...
};
If you really pointer on method, you should replace int (*funcPtr)(int a, int b) by int (Test::*funcPtr)(int a, int b) and use something like that instead:
class Test
{
public:
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
typedef int (Test::*funcPtr)(int a, int b);
int myFunc(funcPtr func, int a, int b)
{
return (this->*func)(a, b);
}
void setup()
{
cout << myFunc(&Test::add, 5, 3) << endl;
cout << myFunc(&Test::sub, 5, 3) << endl;
}
};

You should read about std:: function and std::bind. The first thing will allow you to store a function pointer with multiple form (Functor, lamda, binded), and the second will allow you to bind parameters to your function call (In your case, you want to bind the instance of the class that is needed to call your function).
std:: function<int(int, int)> func = std::bind(&Class::Method, instancePtr, std::placeholders::_1, std:: placeholders::_2);
int result = func(a, b);
However, in your context, your methods should be marked as static (They are not using any non-static member of your class), but the example and the explanation I provided answer to your base question

Firstly, based on your question the best solution here will be without using the pointer instead declare your methods as static and call them directly as given below.
That solution will generate the right results without using the complexity of pointers.
Simple is better if you do not need to use pointers it is better to not use them. code will be more readable as well.
Following code works i tested it:
#include <iostream>
using namespace std;
class Test
{
public:
static int add(int a, int b)
{
return a + b;
}
static int sub(int a, int b)
{
return a - b;
}
void setup()
{
cout << add( 5, 3) << endl;
cout << sub(5, 3) << endl;
}
};
int main()
{
Test test;
test.setup();
}

Related

C++ Reference to member function work around (computation speed)

It is well known that you cannot create a reference to a member function in C++ [source].
For those that don't know. The issue come when you want to do something similar to
class A
{
public:
void Add(int a, int b)
{
std::cout << "Sum is " << a + b << std::endl;
}
void CallAdd(int a, int b, void (*func)(int, int))
{
func(a, b);
}
};
and then call Add through CallAdd:
A a;
a.Add(3, 7); // This works fine
a.CallAdd(3, 7, &a.CallAdd); //This does not compile
The error is
error: cannot create a non-constant pointer to member function
a.CallAdd(3, 7, &a.CallAdd);
Which would not occur if it wiere outside a class.
There is a work around using std::function/lambda. Like this:
class A
{
public:
function<void(int, int)> AddFunc = [](int a, int b)
{
std::cout << "Sum is " << a + b << std::endl;
};
void CallAdd(int a, int b, std::function<void(int, int)> &func)
{
func(a, b);
};
};
int main()
{
A a;
a.CallAdd(3, 7, a.AddFunc);
}
This works fine but the problem is that computation time increases a lot (obviously this is just a minimal reproducible example) compared to simply calling the function.
Is there a way to increase computation speed or is this the best one can do?
For context, I have an algorithm to integrate functions, and I want to change integrands at will so the integrand must be a function parameter.
Pass the function object (or lambda) to a templated member function as follows:
#include <concepts>
#include <iostream>
inline auto myAddFunc = [](int a, int b) {
std::cout << "Sum is " << a + b << std::endl;
};
class A
{
public:
template <std::regular_invocable<int,int> Func>
void CallFunc(int a, int b, Func func)
{
func(a, b);
};
};
int main()
{
A a;
auto mySubFunc = [](int a, int b) {
std::cout << "Difference is " << a - b << std::endl;
};
a.CallFunc(3, 7, myAddFunc);
a.CallFunc(7, 3, mySubFunc);
}

Can I set a value using a function in a class?

If I have a friend function can I somehow use set() to assign a value to a private variable inside the function? Or some other method?
Example : Here I have 3 private variables. I tried to make the sum of 2 of them and store the result in the 3rd one. I tried to do it with a setter but the result is 0. In main it works, but I don't know if I can make it work in the class function.
#include <iostream>
using namespace std;
class Function{
private:
int a;
int b;
int sum;
public:
Function() = default;
Function(int _a, int _b);
friend int sumNumber(Function f);
//Setter and getter
int getA() const;
void setA(int a);
int getB() const;
void setB(int b);
int getSum() const;
void setSum(int sum);
};
Function::Function(int _a, int _b) {
this->a = _a;
this->b = _b;
}
int Function::getA() const {
return a;
}
void Function::setA(int a) {
Function::a = a;
}
int Function::getB() const {
return b;
}
void Function::setB(int b) {
Function::b = b;
}
int Function::getSum() const {
return sum;
}
void Function::setSum(int sum) {
Function::sum = sum;
}
int sumNumber(Function f) {
int a = f.getA();
int b = f.getB();
int sum = a + b;
f.setSum(sum);
return sum;
};
int main() {
Function AA(1,2);
cout << sumNumber(AA);
cout << " " << AA.getSum();
AA.setSum(sumNumber(AA));
cout << "\n" << AA.getSum();
return 0;
}
Output :
3 0
3
As alluded to in the comments, the issue is with this function:
int sumNumber(Function f) {
int a = f.getA();
int b = f.getB();
int sum = a + b;
f.setSum(sum);
return sum;
};
Let us walk through your code:
Function AA(1,2);
You create a object of type Function, called AA and you allocate each member variable of that object via the constructor (1 and 2).
cout << sumNumber(AA);
You call your method (sumNumber) and pass to it a copy of your variable AA. That function adds the two numbers together and internally calls setSum.
cout << " " << AA.getSum();
You now try to display the sum value by calling the getSum method. But the issue was that you passed a copy of your variable into the sumNumber function. The original AA variable was left alone.
To fix this you need to adjust your function by adding an ampersand &. Like this:
int sumNumber(Function& f) {
int a = f.getA();
int b = f.getB();
int sum = a + b;
f.setSum(sum);
return sum;
};
Now your variable AA is being passed by reference and not by value. There are lots of tutorials about this concept.

Is it possible to assign a function to function pointer dynamically?

Is it possible to somehow declare and assign a function to function pointer func in main() without having an actual function add()?
Current Code:
#include <iostream>
int add(int a, int b)
{
return a + b;
}
int main()
{
typedef int (*funcPtr)(int a, int b);
funcPtr func = &add;
std::cout << func(2,3) << std::endl;
}
Preferred Style: (if possible)
#include <iostream>
int main()
{
typedef int (*funcPtr)(int a, int b);
funcPtr func = (funcPtr){return a + b}; // is something like this possible?
std::cout << func(2,3) << std::endl;
}
Is there a way to assign a function to function pointer dynamically like my last code?
You can use lambda; which could convert to function pointer implicitly if capture nothing.
funcPtr func = [](int a, int b) {return a + b;};
LIVE

How to best pass methods into methods of the same class

I have this C++ class that one big complicated method compute that I would like to feed with a "compute kernel", a method of the same class. I figure I would do something along the lines of
class test {
int classVar_ = 42;
int compute_add(int a, int b)
{
compute(int a, int b, this->add_())
}
int compute_mult(int a, int b)
{
compute(int a, int b, this->mult_())
}
int compute_(int a, int b, "pass in add or multiply as f()")
{
int c=0;
// Some complex loops {
c += f(a,b)
// }
return c;
}
int add_(int a, int b){a+b+classVar_;}
int multiply_(int a, int b){a*b+classVar_;}
...
}
but I'm not sure how I would pass in add or multiply.
An alternative to this approach would be to pass in an ENUM of some sort to specify add() or multiply(), but I wanted to avoid a switch or if inside the loops.
What's best practice here?
As you suspected, passing a member function pointer is acceptable practice.
If you need to know the syntax, it is:
int compute_(int a, int b, int (test::*f)(int,int))
{
int c=0;
// Some complex loops {
c += (this->*f)(a,b)
// }
return c;
}
Representing member functions using integers, and switching, introduces programmer overhead to keep things up to date when the list of available operations changes. So you don't want that unless there's some important reason in a particular case.
One alternative is to make compute even more general -- instead of taking a member function, write a function template that takes any callable type:
template <typename BinaryFunction>
int compute_(int a, int b, BinaryFunction f) {
// body as before but `f(a,b)` instead of `(this->*f)(a,b)`
}
This more general template is great if someone wants to use it with some operator of their own invention, that isn't a member function of test. It's more difficult to use in the case of the member function, though, because someone needs to capture this. There are a few ways to do that -- a C++11 lambda, boost::bind, or writing out a functor longhand. For example:
template <typename BinaryFunction>
int compute_(int a, int b, BinaryFunction f) {
// body as before with `f(a,b)`
}
int compute_(int a, int b, int (test::*f)(int,int))
{
return compute_(a, b, bind_this(f, this));
}
Defining bind_this is a bit of a pain: it's like std::bind1st except that we'd like to work with a 3-arg functor whereas bind1st only takes a binary functor. boost::bind, and std::bind in C++11, are more flexible, and will handle the extra arguments. The following will do for this case, but doesn't work in general to bind 2-arg member functions:
struct bind_this {
int (test::*f)(int,int);
test *t;
int operator(int a, int b) const {
return (t->*f)(a,b);
}
bind_this(int (test::*f)(int,int), test *t) : f(f), t(t) {}
};
In C++11 you can just use a lambda:
int compute_(int a, int b, int (test::*f)(int,int))
{
return compute_(a, b, [=](int c, int d){ return (this->*f)(c,d) });
}
Use pointers to functions.
int compute(int a, int b, int (test::*f) (int, int) )
{
int c=0;
// Some complex loops {
c += (this->*f)(a,b)
// }
return c;
}
You have two alternatives :
using pointer to member function
using lambda functions
Example using pointer to member function :
#include <iostream>
class D
{
public:
D(int v ) : classVar_(v){}
int add_(int a, int b){return (a+b+classVar_);}
int multiply_(int a, int b){return (a*b+classVar_);}
private:
int classVar_;
};
class test {
public:
int compute_(int a, int b, D &d, int (D::*f)(int a, int b))
{
int c=0;
// Some complex loops {
c += (d.*f)(a,b);
// }
return c;
}
};
int main()
{
test test;
D d(1);
std::cout<<"add : " << test.compute_( 5, 4, d, &D::add_ ) << std::endl;
std::cout<<"add : " << test.compute_( 5, 4, d, &D::multiply_ ) << std::endl;
}
Example using lambda :
#include <iostream>
#include <functional>
class D
{
public:
D(int v ) : classVar_(v){}
int add_(int a, int b){return (a+b+classVar_);}
int multiply_(int a, int b){return (a*b+classVar_);}
private:
int classVar_;
};
class test {
public:
int compute_(int a, int b, std::function< int(int,int) > f)
{
int c=0;
// Some complex loops {
c += f(a,b);
// }
return c;
}
};
int main()
{
test test;
D d(1);
std::cout<<"add : " << test.compute_( 5, 4, [&d](int a, int b){ return d.add_(a,b); } ) << std::endl;
std::cout<<"add : " << test.compute_( 5, 4, [&d](int a, int b){ return d.multiply_(a,b); } ) << std::endl;
}

operator as template parameter

Is it possible?
template<operator Op> int Calc(int a, b)
{ return a Op b; }
int main()
{ cout << Calc<+>(5,3); }
If not, is way to achieve this without ifs and switches?
You could use functors for this:
template<typename Op> int Calc(int a, int b)
{
Op o;
return o(a, b);
}
Calc<std::plus<int>>(5, 3);
No - templates are about types or primitive values.
You can nontheless pass so called function objects that can be called like functions and carry the desired operator functionality (despite having a nice syntax).
The standard library defines several ones, e.g. std::plus for addition ...
#include <functional>
template<typename Op>
int Calc(int a, int b, Op f) {
return f(a, b);
}
int main() {
cout << Calc(5,3, std::plus());
cout << Calc(5,3, std::minus());
}
You can do this using polymorphism:
#include <cstdlib>
#include <iostream>
using namespace std;
class Operator
{
public:
virtual int operator()(int a, int b) const = 0;
};
class Add : public Operator
{
public:
int operator()(int a, int b) const
{
return a+b;
}
};
class Sub : public Operator
{
public:
int operator()(int a, int b) const
{
return a-b;
}
};
class Mul : public Operator
{
public:
int operator()(int a, int b) const
{
return a*b;
}
};
int main()
{
Add adder;
cout << adder(1,2) << endl;
Sub suber;
cout << suber(1,2) << endl;
Mul muler;
cout << muler(1,2) << endl;
return 0;
}
If you refer to global operators, you have already received some answers. In some particular cases, though, it might also be helpful to use overloaded operator functions.
This might be trivial; nevertheless it might be helpful in some cases which is why I post one example:
#include <iostream>
template<typename opType, typename T>
int operation(opType op, T a, T b)
{
return (a.*op)(1) + (b.*op)(1);
}
struct linear
{
int operator()(int n) const {return n;}
int operator[](int n) const {return n * 10;}
};
int main()
{
linear a, b;
std::cout << operation(&linear::operator(), a, b) << std::endl
<< operation(&linear::operator[], a, b);
return 0;
}
output:
2
20
Use
template<typename Op>
int Calc(int a, int b, Op f) {
return f(a, b);
}
int
main() {
cout << Calc(5, 3, std::plus{});
cout << Calc(5, 3, std::minus{});
}
if Dario answer fails with error: cannot deduce template arguments for ‘plus’ from ()