简体   繁体   中英

What's the function signature of a member function?

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?

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
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;
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;
}

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 .

The answer is in the doc .

Pointer to member declarator: the declaration SC::* D; declares D as a pointer to non-static member of C of type determined by decl-specifier-seq S .

 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM