![](/img/trans.png)
[英]Use Class Member Function Pointer before Class Definition C++
[英]C++ Member Function Pointer Definition
考虑以下代码:
#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();
}
似乎后一版本不接受具有额外cv限定符的函数。
是什么指定一个功能构件指针这样的区别C (M::*member)()
和这样C (M::*member)
?
让我们简化为仅考虑以下两者之间的区别:
template <class C, class M> void f(C (M::*member)());
template <class C, class M> void g(C (M::*member));
在f
, member
是指向M
的成员函数的指针,返回零参数并返回C
如果用&B::func
调用它,编译器将推导出M == B
和C == void
。 直截了当。
在g
, member
只是指向C
类型的M
成员的指针。 但是,在我们的例子中, &B::func
是一个函数。 所以这里的影响就是放弃指针。 我们再次推导出M == B
,而C
变为void()
- 现在C
是一个函数类型。 这是f
一个不太专业的版本,因为它允许更多种类的成员。 g
可以匹配带参数的函数,也可以匹配指向成员的指针,或相关地反对cv -qualified member functinos。
让我们考虑一个例子,一个重载函数以及如何以不同方式推导它(这是你问题中的原始问题,已经编辑过,但仍然很有趣):
struct X {
void bar() { }
void bar(int ) { }
};
当我们这样做时:
f(&X::bar);
即使&X::bar
是一个重载的名称,只有一个实际匹配C (M::*)()
。 具有M == X
和C == void
那个。 采用int
的bar
的重载根本不可能与模板类型匹配。 所以这是传递重载名称的可接受用途之一。 这推断罚款。
但是,当我们这样做时:
g(&X::bar);
现在,有两个完美的减价。 C
可以是void()
和void(int)
。 由于两者都是有效的,因此推论是不明确的,并且您无法编译 - 错误并不能使这一点特别清楚。
现在回到你的例子:
call1(&B::func2, this); // Error: no matching member function for call to 'call2'
call2(&B::func2, this); // works
&B::func2
的类型是void (B::*)() const volatile
。 由于call1
推断出一个不带args但不是cv-qualified的成员函数类型,所以类型推导就会失败。 没有C
或M
可以匹配这些类型。
但是, call2
扣除很好,因为它更通用。 它可以匹配任何指向成员的指针。 我们最终只得到C = void() const volatile
。 这就是为什么这样做的原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.