I am trying to write a function that would take in a generic function pointer as an argument.
Suppose you have a class A
and its derivatives like below
class A {
};
class A1: public A {
};
class A2: public A {
};
class A3: public A {
};
I have another function
void registerCallback(std::function<void(A*)> func_ptr) {
}
int main() {
std::function<void(A1*)> fptr= [&](A1*) {
cout << "dummy" <<endl;
};
registerCallback(fptr); /// throws error
}
It tells you, cannot convert std::function<void(A*)>
to std::function<void(A1*)>
How can I solve this problem?
CodePudding user response:
How can I solve this problem?
You can use A*
instead of A1*
in the definition of fptr
.
std::function<void(A1*)> fptr= [&](A*) {
cout << "dummy" <<endl;
};
It is instructive to understand why your code is erroneous, not just from a syntactic point of view but also from a semantic point of view.
From a syntactic point of view, A1*
can be used where A*
where is expected -- it is an automatic pointer conversion. However, std::function<void(A1*)>
cannot be used where std::function<void(A*)>
is expected. There is no automatic conversion.
It's more important to understand the semantic problem if that was not a syntactic error. Let's say for the sake of this discussion that the language/compiler accepted your code. Let's take the code a bit further. Update your code to the following:
class A {
};
class A1: public A {
public:
int int_var;
};
class A2: public A {
public:
double double_var;
};
class A3: public A {
public:
std::string string_var;
};
static std::function<void(A*)> registered_function_ptr;
void registerCallback(std::function<void(A*)> func_ptr) {
registered_function_ptr = fun_ptr;
}
void callRegisteredFunction(A* a_ptr) {
registered_function_ptr(a_ptr);
}
int main() {
std::function<void(A1*)> fptr= [&](A1* a1_ptr) {
// Expecting a pointer to an A1 object.
// Should be able to use members of A1.
cout << "int_var: " << a1_ptr->int_var << endl;
};
registerCallback(fptr);
A2 a2;
a2.double_var = 20;
// Syntactically correct.
callRegisteredFunction(&a2);
A3 a3;
a3.string_var = "Some string";
// Also syntactically correct.
callRegisteredFunction(&a3);
}
When callRegisteredFunction
is executed, it calls the registered function. In this case it is fptr
. fptr
expects a pointer to an A1
object but we are able to call it indirectly with objects that are different -- they don't have int_var
. Instead, they have double_var
and string_var
. That will definitely lead to undefined behavior. The compiler and the language are preventing you falling into that trap.
CodePudding user response:
Just declare fptr
as a callable object with parameter of basic type - std::function<void(A*)>
. It will still accept all classes (publicly) derived from A
:
int main() {
std::function<void(A*)> fptr= [&](A*) {
std::cout << "dummy" << std::endl;
};
A1 *a = new A1{};
fptr(a); // all good
}