成员函数的函数签名是什么?

What's the function signature of a member function?

本文关键字:函数 是什么 成员      更新时间:2023-10-16

我很难理解功能签名和指针。

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   
}

我的编译器说myStruct::nonstaticFunc()的类型是void (myStruct::*)(),但不是指向它的指针的类型吗?

我在问,因为当您创建一个std::function对象时,您会传递要指向的函数的功能签名,例如:

std::function<void()> funcPtr;      // Pointer to function with signature void()
not 
std::function<void(*)()> funcPtr;

如果我必须根据void()的模式进行猜测,我会说:

void myStruct::();
or
void (myStruct::)();

但这是不对的。我不明白为什么我应该添加一个星号,因为它是非静态而不是静态的。换句话说,指针void(* )()点可以用签名void()来函数,而指针void(myStruct::*)()点可以用签名功能进行功能?

对我来说,似乎对成员指针是什么是基本的误解。例如,如果您有:

struct P2d {
    double x, y;
};

成员指针double P2d::*mp = &P2d::x;不能指向特定 P2d实例的x坐标,而是对名称x的"指针":要获得Double,您需要提供P2d实例您正在寻找...例如:

P2d p{10, 20};
printf("%.18gn", p.*mp); // prints 10

同样适用于成员功能...例如:

struct P2d {
    double x, y;
    double len() const {
        return sqrt(x*x + y*y);
    }
};
double (P2d::*f)() const = &P2d::len;

其中f不是指向特定实例的成员函数的指针,并且需要使用

调用this
printf("%.18gn", (p.*f)());

f换句话说,只是的"选择器"> P2d的哪个const成员函数接受不接受参数并返回您对double。在这种特定情况下(由于只有一个成员函数兼容)可以使用零位存储该选择器(您可以设置指针为&P2d::len的唯一可能的值)。

一开始不理解成员指针,请不要感到羞耻。他们确实有点"奇怪",而C 程序员也不理解它们。

说实话,它们也不是真正有用的:最经常需要的是一个指向特定实例的方法的指针

C 11提供了std::function包装器和lambdas:

std::function<double()> g = [&](){ return p.len(); };
printf("%.18gn", g()); // calls .len() on instance p
std::function<void()> funcPtr = std::bind(&myStruct::nonstaticFunc, obj);

是您将成员函数存储在std::function中的方式。必须在有效对象上调用成员函数。


如果要将对象的通过延迟到以后,则可以这样完成:

#include <functional>
#include <iostream>
struct A {
    void foo() { std::cout << "A::foon"; }
};
int main() {
    using namespace std::placeholders;
    std::function<void(A&)> f = std::bind(&A::foo, _1);
    A a;
    f(a);
    return 0;
}

std::bind将为您处理细节。std::function仍然必须具有常规函数的签名,因为它的类型参数。但是,如果将对象显示为函数的参数,则可以掩盖成员。


addenum
为了分配std::function,您甚至不需要std::bind即可绑定对象的较晚绑定,只要原型正确:

std::function<void(A&)> f = &A::foo;
p = &myStruct::staticFunc;    // Works fine
p = &myStruct::nonstaticFunc; // Type mismatch

原因:函数到点转换永远不会应用非静态成员函数,因为含有非静态成员函数的lVALUE无法获得。


pointer void(*)()指向签名void()和指针void(mystruct ::*)()指向签名功能的功能?

myStruct::是为了确保 myStruct非静态成员函数被调用(不是其他结构,如下所示):

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

当您使用指针,std :: function或std :: bind bind to to to to to to to to to to to to to class foo的非静态成员函数(即"方法"),第一个param必须是类FOO的具体对象,因为非静态方法必须由混凝土对象调用,而不是由类。

更多详细信息:std ::功能和std :: bind。

答案在文档中。

指向会员声明器的指针:声明S C::* D;D声明为 由C的非静态成员的指针确定的 deck-decifier-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
}

没有签名void ()的功能。void (*)()对于foo的函数或void (foo::*)()。星号是强制性的,因为它是x的指针。std::function与此无关。

注意:您的困惑是void()void (*)()相同的签名。甚至int()&lt; => int (*)()。也许您认为可以编写int (foo::*)以具有方法指针。但这是数据成员指针,因为括号是可选的,int (foo::*)&lt; => int foo::*

要避免使用这种模糊的语法,您需要用返回类型,星号和他的参数编写指针/成员。