简体   繁体   English

C ++成员函数指针定义

[英]C++ Member Function Pointer Definition

Consider this code: 考虑以下代码:

#include <iostream>
#include <functional>

struct B {
    template <class C, class M, class T>
    void call1(C (M::*member)(), T *instance) {
        std::function<void()> fp = std::bind(member, instance);
        fp();
    }

    template <class C, class M, class T>
    void call2(C (M::*member), T *instance) {
        std::function<void()> fp = std::bind(member, instance);
        fp();
    }

    void foo() {
        call1(&B::func, this); // works
        call2(&B::func, this); // works

        call1(&B::func2, this); // Error: no matching member function for call to 'call2'
        call2(&B::func2, this); // works
    }

    void func() {
        std::cout << "func\n";
    }

    void func2() const volatile {
        std::cout << "func2\n";
    }
};

int main() {
    B{}.foo();
}

It seems that the later version don't accept functions with extra cv qualifiers. 似乎后一版本不接受具有额外cv限定符的函数。

What is the difference between specifying a function member pointer like this C (M::*member)() and like this C (M::*member) ? 是什么指定一个功能构件指针这样的区别C (M::*member)()和这样C (M::*member)

Let's simplify to just considering the difference between: 让我们简化为仅考虑以下两者之间的区别:

template <class C, class M> void f(C (M::*member)());
template <class C, class M> void g(C (M::*member));

In f , member is a pointer to a member function of M returning taking zero arguments and returning C . fmember是指向M的成员函数的指针,返回零参数并返回C If you called it with &B::func , the compiler will deduce M == B and C == void . 如果用&B::func调用它,编译器将推导出M == BC == void Straightforward. 直截了当。

In g , member is just a pointer to a member of M of type C . gmember只是指向C类型的M成员的指针。 But, in our case, &B::func is a function. 但是,在我们的例子中, &B::func是一个函数。 So the impact here is just dropping the pointer. 所以这里的影响就是放弃指针。 We deduce M == B again, whereas C becomes void() - now C is a function type. 我们再次推导出M == B ,而C变为void() - 现在C是一个函数类型。 This is a less specialized version of f in that it allows for more kinds of members. 这是f一个不太专业的版本,因为它允许更多种类的成员。 g can match against functions that take arguments, or against pointers to members, or, relevantly, against cv -qualified member functinos. g可以匹配带参数的函数,也可以匹配指向成员的指针,或相关地反对cv -qualified member functinos。

Let's consider as an example an overloaded function and how it would get deduced differently (this was the original problem in your question, which has since been edited, but is still interesting): 让我们考虑一个例子,一个重载函数以及如何以不同方式推导它(这是你问题中的原始问题,已经编辑过,但仍然很有趣):

struct X {
    void bar() { }
    void bar(int ) { }
};

When we do: 当我们这样做时:

f(&X::bar);

Even though &X::bar is an overloaded name, only one actually matches C (M::*)() . 即使&X::bar是一个重载的名称,只有一个实际匹配C (M::*)() The one that has M == X and C == void . 具有M == XC == void那个。 There is simply no way that the overload of bar taking an int matches the template type. 采用intbar的重载根本不可能与模板类型匹配。 So this is one of the acceptable uses of passing an overloaded name. 所以这是传递重载名称的可接受用途之一。 This deduces fine. 这推断罚款。

However, when we do: 但是,当我们这样做时:

g(&X::bar);

Now, there are two perfectly vaild deductions. 现在,有两个完美的减价。 C could be both void() and void(int) . C可以是void()void(int) Since both are valid, the deduction is ambiguous, and you fail to compile - with an error that doesn't really make this particularly clear. 由于两者都是有效的,因此推论是不明确的,并且您无法编译 - 错误并不能使这一点特别清楚。


Now back to your example: 现在回到你的例子:

call1(&B::func2, this); // Error: no matching member function for call to 'call2'
call2(&B::func2, this); // works

The type of &B::func2 is void (B::*)() const volatile . &B::func2的类型是void (B::*)() const volatile Since call1 deduces on a member function type that takes no args and isn't cv-qualified, the type deduction simply fails. 由于call1推断出一个不带args但不是cv-qualified的成员函数类型,所以类型推导就会失败。 There is no C or M to get those types to match. 没有CM可以匹配这些类型。

However, the call2 deduction is fine since it is more generic. 但是, call2扣除很好,因为它更通用。 It can match any pointer to member. 它可以匹配任何指向成员的指针。 We simply end up with C = void() const volatile . 我们最终只得到C = void() const volatile That's why this works. 这就是为什么这样做的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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