指向 Parent Class 成员方法的指针

Pointer to Parent Class Member Method

我正在尝试让以下简单代码工作:

#include <functional>
#include <iostream>

class Parent {
public:
    void method(int a) {
        std::cout << "Parent::method(" << a << ")" << std::endl;
    }
};

class Child : public Parent {
public:
    
};

template <typename T>
std::function<void()> test(T* v, void(T::* fn)(int)) {
    return std::function<void()>([v, fn](){
        v->fn(10);
    });
}

int main() {
    Child c;
    
    std::function<void()> fn = test(&c, &Child::method);
    
    fn();
    
    return 1;
}

但出现以下错误:

note:   template argument deduction/substitution failed:
note:   deduced conflicting types for parameter 'T' ('Child' and 'Parent')
  std::function<void()> fn = test(&c, &Child::method);

如果我将指针更改为 Parent::method,我会遇到同样的问题。既然Child“是一个”parent,为什么编译器无法推导出这个模板?

谢谢!

Child "is a" parent

是面向对象意义上的。但是模板参数推导主要是关于类型 identity.

&Child::method 命名了 Parent 的成员。它可能在 Child 中可访问,但在 Parent 中声明。因此,该成员唯一可用的扣除 TParent。另一方面,指针将 T 推断为 Child。这里T身份无法唯一确定。所以推演失败

但我们仍然可以通过调整来编写您的函数模板:

template <class C, class P>
std::function<void()> test(C* v, void(P::* fn)(int)) {
    return std::function<void()>([v, fn](){
        (v->*fn)(10);
    });
}

现在 类 是在各自的上下文中推导出来的,不会影响其他的。这可能就足够了(因为 (v->*fn)(10) 对于不相关的 类 将是错误格式的)。但是可能会进行额外的检查以使过载 sfinae 友好。

指针&Child::method是指向Parent中方法的成员函数指针。 Child 可以 访问 这个方法的事实与模板参数推导无关。编译器看到并根据第一个参数为 T 参数推导出 Parent。同时根据第一个参数&c推导出ChildT。这会发生冲突,您会收到错误消息。

您可以通过将函数模板的第二个参数放在非推导上下文中来解决这个问题

template <typename T>
struct I { using type = T; };

template <typename T>
std::function<void()> test(T* v, void(I<T>::type::* fn)(int)) {
                                   // ^________^  T here is not deduced
    return std::function<void()>([v, fn](){
        (v->*fn)(10);
    });
}

现在模板参数推导不受影响,但您仍然可以调用 method,因为它可以从 Child class.

访问