是的,你的程序不合格。
C++ 17(N4659)[namespace.udecl]/16(重點煤礦):
For the purpose of overload resolution, the functions that are introduced by a using-declaration into a derived class are treated as though they were members of the derived class. In particular, the implicit this
parameter shall be treated as if it were a pointer to the derived class rather than to the base class. This has no effect on the type of the function, and in all other respects the function remains a member of the base class.
換句話說,所述using聲明不添加的B
一個構件,它只是爲同一個成員添加第二個名字A::f
。這個第二個名字可以通過名稱查找來選擇,並用於名稱使用的可訪問性檢查,但除此之外,除了重載解析所指出的,它與原始成員相同。
[expr.unary.op/3:
The result of the unary &
operator is a pointer to its operand. The operand shall be an lvalue or a qualified-id. If the operand is a qualified-id naming a non-static or variant member m
of some class C
with type T
, the result has type "pointer to member of class C
of type T
" and is a prvalue designating C::m
.
因此,即使合格-ID您使用的是拼寫的class B
名稱和限定名稱查找B::f
發現通過引入的名字所述using聲明在B
,實際函數表達式名稱是A
的成員,所以表達式&B::f
具有類型「指針)返回void
(類型函數的A
類的成員」,或作爲type-id,void (A::*)()
。您可以通過添加到您的例子驗證這一點:
#include <type_traits>
static_assert(std::is_same<decltype(&B::f), void (A::*)()>::value, "error");
最後,在[conv.mem/2:
A prvalue of type "pointer to member of B
of type cvT
", where B
is a class type, can be converted to a prvalue of type "pointer to member of D
of type cvT
", where D
is a derived class of B
. If B
is an inaccessible, ambiguous, or virtual base class of D
, or a base class of a virtual base class of D
, a program that necessitates this conversion is ill-formed.
所以命名的成員函數指針是有效的,但是從void (A::*)()
將其轉換到void (B::*)()
不是,因爲繼承是從main
無法訪問。
作爲一種變通方法,您可以提供訪問成員函數指針,除了成員函數本身B
:
struct B : private A
{
using A::f;
using func_ptr_type = void (B::*)();
static constexpr func_ptr_type f_ptr = &A::f;
};
或者,如果你真的必須使用C樣式轉換。在某些情況下,允許C風格的轉換忽略類繼承關係的可訪問性,其中C++風格轉換無法用相同的結果進行編譯。 (reinterpret_cast
也可以將任何指向成員函數的指針轉換爲任何其他指針,但其結果未指定。)
int main()
{
B b;
void (B::*f)() = (void (B::*)()) &B::f;
(b.*f)();
}
在連接到這一問題的意見。注意:如果你改變main
到
那麼f
類型是void (A::*)()
如上所述。但你碰上[expr.mptr.oper/2(重點煤礦再次):
The binary operator .*
binds its second operand, which shall be of type "pointer to member of T
" to its first operand, which shall be a glvalue of class T
or of a class of which T
is an unambiguous and accessible base class.
所以,你還是有問題的成員函數與原來的類關聯,不能被認爲是B
的成員除B
和任何朋友的範圍外。
將有問題的行更改爲'auto f = &B::f;'會使該行進行編譯,但gcc會在下一行報告錯誤,(b。* f)();',抱怨:「error:'A'是「B」的難以接近的基礎「。嗯.... –
@ SamVarshavchik:鏗鏘似乎表現相同的方式。 – 3442