There is a misunderstanding of how classes work.
int main()
{
B obj(sum_fun); // calls B constructor with parameter `sum_fun`
obj.fb(); // calls member function B::fb() with no parameters
return 0;
}
Both lines raise an error as
- Your class has no constructor which takes a single parameter.
void fb()(F f1)
is illegal syntax. To declare a member function, use only one set of parentheses: either void fb()
or void fb(F f1)
. The latter is incorrect in our case, as your member function call obj.fb()
passes no parameters.
To fix this, write up a constructor, store the function as a member variable, and use that variable in the function fb()
.
template <typename F>
class B
{
public:
// constructor, initialises member `m_func` through member initialisation
B(F func) : m_func(func) {}
void fb()
{
m_func(10.1,10.2);
}
private:
F m_func;
};
In C++17, thanks to automatic template deduction, no errors are now emitted. But in lower standards (e.g. C++11), template deduction is lacking and thus, the full templated type needs to be specified when declaring obj
.
So in standards below C++17, the main function should be:
int main()
{
// C++11: using a function pointer to denote type
B<double(*)(const double&, const double&)> obj(sum_fun);
// ok in C++17, looks cleaner too
// B obj(sum_fun);
obj.fb();
return 0;
}
Here, double(*)(const double&, const double&)
is a function pointer, i.e. a pointer to a function which returns a double
and takes two parameters, both of type const double&
. Function pointers may be considered as a type, which satisfies the template (template<typename F>
).
Just like we do std::vector<int>
and std::vector<double>
, we can also do std::vector<double(*)(const double&, const double&)>
to denote a vector of functions returning double
and taking const double&
as parameters.
And by the way, sum_fun
also raises a warning: nothing is returned even though the return type is double
... better specify void
as the return type instead.
C++11 Demo
C++17 Demo
Is it possible to pass function as argument directly to B::fb()
instead of creating constructor B::B(F)
and storing in local variable?
Certainly.
#include <iostream>
void sum_fun(const double& a, const double& b)
{
std::cout << a+b << "\n";
}
template <typename F>
class B
{
public:
void fb(F func)
{
func(10.1,10.2);
}
};
int main()
{
B<void(*)(const double&, const double&)> obj;
obj.fb(sum_fun);
return 0;
}
Note that the member function fb
now takes a single parameter func
, which we then call. Note also that in C++17, we now can't instantiate the obj
with B obj;
because this would be ambiguous and the template can't be deduced automatically. Instead, we need to specify the full type B<void(*)(const double&, const double&)>
.
However, a recommended alternative over function pointers is to use std::function
, which is more versatile and offers a more readable syntax. (std::function
Demo)