![](/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.