Reputation: 14434
I'm having trouble understanding function signatures and pointers.
struct myStruct
{
static void staticFunc(){};
void nonstaticFunc(){};
};
int main()
{
void (*p)(); // Pointer to function with signature void();
p = &myStruct::staticFunc; // Works fine
p = &myStruct::nonstaticFunc; // Type mismatch
}
My compiler says that the type of myStruct::nonstaticFunc()
is void (myStruct::*)()
, but isn't that the type of a pointer pointing to it?
I'm asking because when you create an std::function
object you pass the function signature of the function you want it to point to, like:
std::function<void()> funcPtr; // Pointer to function with signature void()
not
std::function<void(*)()> funcPtr;
If I had to guess based on the pattern of void()
I would say:
void myStruct::();
or
void (myStruct::)();
But this isn't right. I don't see why I should add an asterisk just because it's nonstatic as opposed to static. In other words, pointer void(* )()
points to function with signature void()
, and pointer void(myStruct::*)()
points to function with signature what?
Upvotes: 14
Views: 6167
Reputation: 170269
std::function<void()> funcPtr = std::bind(&myStruct::nonstaticFunc, obj);
Is how you store a member function in std::function
. The member function must be called on a valid object.
If you want to delay the passing of an object until later, you can accomplish it like this:
#include <functional>
#include <iostream>
struct A {
void foo() { std::cout << "A::foo\n"; }
};
int main() {
using namespace std::placeholders;
std::function<void(A&)> f = std::bind(&A::foo, _1);
A a;
f(a);
return 0;
}
std::bind
will take care of the details for you. std::function
still must have the signature of a regular function as it's type parameter. But it can mask a member, if the object is made to appear as a parameter to the function.
Addenum:
For assigning into std::function
, you don't even need std::bind
for late binding of the object, so long as the prototype is correct:
std::function<void(A&)> f = &A::foo;
Upvotes: 5
Reputation: 13994
p = &myStruct::staticFunc; // Works fine
p = &myStruct::nonstaticFunc; // Type mismatch
Reason : A function-to-pointer conversion never applies to non-static member functions because an lvalue that refers to a non-static member function cannot be obtained.
pointer void(* )() points to function with signature void(), and pointer void(myStruct::*)() points to function with signature what?
myStruct::
is to make sure that the non-static member function of struct myStruct
is called (not of other structs, as shown below) :
struct myStruct
{
static void staticFunc(){};
void nonstaticFunc(){};
};
struct myStruct2
{
static void staticFunc(){};
void nonstaticFunc(){};
};
int main()
{
void (*p)(); // Pointer to function with signature void();
void (myStruct::*f)();
p = &myStruct::staticFunc; // Works fine
p = &myStruct2::staticFunc; // Works fine
f = &myStruct::nonstaticFunc; // Works fine
//f = &myStruct2::nonstaticFunc; // Error. Cannot convert 'void (myStruct2::*)()' to 'void (myStruct::*)()' in assignment
return 0;
}
Upvotes: 1
Reputation: 114599
To me there seems to be a basic misunderstanding of what a member pointer is. For example if you have:
struct P2d {
double x, y;
};
the member pointer double P2d::*mp = &P2d::x;
cannot point to the x
coordinate of a specific P2d
instance, it is instead a "pointer" to the name x
: to get the double you will need to provide the P2d
instance you're looking for... for example:
P2d p{10, 20};
printf("%.18g\n", p.*mp); // prints 10
The same applies to member functions... for example:
struct P2d {
double x, y;
double len() const {
return sqrt(x*x + y*y);
}
};
double (P2d::*f)() const = &P2d::len;
where f
is not a pointer to a member function of a specific instance and it needs a this
to be called with
printf("%.18g\n", (p.*f)());
f
in other words is simply a "selector" of which of the const member functions of class P2d
accepting no parameters and returning a double
you are interested in. In this specific case (since there is only one member function compatible) such a selector could be stored using zero bits (the only possible value you can set that pointer to is &P2d::len
).
Please don't feel ashamed for not understanding member pointers at first. They're indeed sort of "strange" and not many C++ programmers understand them.
To be honest they're also not really that useful: what is needed most often is instead a pointer to a method of a specific instance.
C++11 provides that with std::function
wrapper and lambdas:
std::function<double()> g = [&](){ return p.len(); };
printf("%.18g\n", g()); // calls .len() on instance p
Upvotes: 12
Reputation: 26765
The answer is in the doc.
Pointer to member declarator: the declaration
S C::* D;
declaresD
as a pointer to non-static member ofC
of type determined by decl-specifier-seqS
.struct C { void f(int n) { std::cout << n << '\n'; } }; int main() { void (C::* p)(int) = &C::f; // pointer to member function f of class C C c; (c.*p)(1); // prints 1 C* cp = &c; (cp->*p)(2); // prints 2 }
There are no function with signature void ()
. There are void (*)()
for a function or void (foo::*)()
for a method of foo
. The asterisk is mandatory because it's a pointer to x. std::function
has nothing to do with that.
Note: Your confusion is that void()
is that same signature that void (*)()
. Or even int()
<=> int (*)()
. Maybe you think that you can write int (foo::*)
to have a method pointer. But this is a data member pointer because the parenthesis are optional, int (foo::*)
<=> int foo::*
.
To avoid such obscure syntax you need to write your pointer to function/member with the return type, the asterisk and his parameters.
Upvotes: 0
Reputation: 75
When you use a pointer, std::function or std::bind to refer to a non-static member function (namely, "method" of class Foo), the first param must be a concrete object of class Foo, because non-static method must be called by a concrete object, not by Class.
More details: std::function and std::bind.
Upvotes: 0