We have an usual class hierarchy:
class B
{
public:
int x;
B() : x(0) {}
virtual ~B() {}
};
class D : public B
{
public:
int y;
D() : y(0) {}
};
And a function that takes one argument - reference to a base class object.
void b_set(B& b)
{
b.x = 5;
}
Then, I want to create function pointer of type void (D&)
and store b_set
in it. This should be valid operation, as all objects legally passed to function pointer call must be also of type B. Yet it isn't allowed.
typedef void (*fp_d_mutator)(D&);
void fp_test(D& obj)
{
fp_d_mutator fun = b_set; //invalid conversion from 'void (*)(B&)' to 'fp_d_mutator {aka void (*)(D&)}
fun(obj);
}
#include <functional>
typedef std::function<void (D&)> stdfun_d_mutator;
void stdfun_test(D& obj)
{
stdfun_d_mutator fun = b_set; //works
fun(obj);
}
So...
A function that takes an argument of type B&
is not a function that takes an argument of type D&
. While D&
is convertible to B&
, they are not the same type. If you could store a pointer to a function that takes B&
as a pointer to D&
, how would the compiler know when to convert the argument? (Note that the conversion sometimes requires adjusting a pointer)
The difference in std::function
is that the calling signature (here D&
) is part of the function object's type, and the called signature (here B&
) is part of the internal storage. So when you apply the function objects' operator()
the code that implements operator()(D&)
takes care of the conversion.