A simplified example from a recent blog post:
struct B { void f(); };
struct D : B { };
constexpr auto as_d = static_cast<void(D::*)()>(&D::f); // (1)
template <void (D::*)()>
struct X { };
X<as_d> x; // (2)
gcc, clang, and MSVC all accept the declaration of as_d
marked (1)
. gcc and clang both reject the declaration of x
marked (2)
, but MSVC accepts it.
Both gcc's and clang's error messages indicate that they know that as_d
is a pointer to member of B
. clang:
<source>:9:3
: error: sorry, non-type template argument of pointer-to-member typevoid (D::*)()
that refers to memberB::f
of a different class is not supported yet
gcc:
<source>:9:7
: error:void (D::*)(){((void (D::*)())B::f), 0}
is not a valid template argument for typevoid (D::*)()
Who is right? If gcc/clang, what is the rule we're running afoul of? It sure seems like as_d
is a converted constant expression of type void (D::*)()
to me...
Explanation: A base class pointer can point to a derived class object, but we can only access base class member or virtual functions using the base class pointer because object slicing happens when a derived class object is assigned to a base class object.
Derived class pointer cannot point to base class.
A pointer to derived class is a pointer of base class pointing to derived class, but it will hold its aspect. This pointer of base class will be able to temper functions and variables of its own class and can still point to derived class object.
The pointer to member operators . * and ->* are used to bind a pointer to a member of a specific class object. Because the precedence of () (function call operator) is higher than . * and ->* , you must use parentheses to call the function pointed to by ptf .
Well, this ended up being pretty interesting. As far as the language is concerned, the program is valid - as_d
does meet the requirement for being a valid non-type template argument (it is a converted constant expression of the right type).
However, the Itanium C++ ABI apparently does not specify a mangling for this situation (that is, having a non-type template argument whose type is a pointer-to-member-to-derived but whose value is a pointer-to-member-to-base). Compilers targeting that ABI (i.e. clang and gcc), as a result, can't accept this code. This explains why clang's error is "sorry, not yet" rather than "no, bad!"
On the other hand, other ABIs have no such mangling problem, and so MSVC and ICC are both able to compile the program just fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With