Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting a pointer-to-member-of-base to a pointer-to-member-of-derived

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 type void (D::*)() that refers to member B::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 type void (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...

like image 895
Barry Avatar asked Aug 19 '18 14:08

Barry


People also ask

How a base class pointer can be converted to derived class member?

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.

Can a derived pointer point to a base class?

Derived class pointer cannot point to base class.

What is a pointer to derived 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.

Which pointer is used in pointer to member function?

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 .


1 Answers

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.

like image 59
Barry Avatar answered Oct 08 '22 13:10

Barry