8

Member function pointers can not be reinterpret_cast to function pointers. (GCC requires the -pedantic-errors flag to enforce that, though.)

However GCC, Clang and MSVC seem to agree that casting a member function pointer to a reference to function pointer is ok. See the following example:

#include<type_traits>

struct A {
    void f() {}
};

int main() {
    auto x = &A::f;
    auto y = reinterpret_cast<void(*&)()>(x);
    // auto y = reinterpret_cast<void(*)()>(x);
    static_assert(std::is_same_v<decltype(y), void(*)()>);
}

Godbolt here

This program compiles on all three compilers, but fails to compile on all (with pedantic flags) when the out-commented line is used instead of the previous one.

I don't see any rule in the standard allowing this conversion. Is the program ill-formed and the compilers fail to diagnose it or is the program well-formed?

If the latter, what is the exact conversion sequence, where does the standard allow it and can the function pointer be converted back to the original type in order to call it or is the use of the reference for initialization of y already undefined behavior?

4
  • What happens if A::f is virtual? Commented Nov 28, 2019 at 18:06
  • @PeteBecker It doesn't seem to make a difference to the compilers. Commented Nov 28, 2019 at 18:08
  • C++ may have a sharp edge, or two. This seems like one of them. Commented Nov 28, 2019 at 18:11
  • @uneven_mark -- okay, thanks. Red herring. Commented Nov 28, 2019 at 19:30

1 Answer 1

7

reinterpret_cast<T&>(x) is equivalent to *reinterpret_cast<T*>(&x).

In other words, reinterpret_cast<void(*&)()>(x) performs type punning on the pointer itself.

Accessing the result of this cast violates strict aliasing and causes undefined behavior, as usual.


I don't see any rule in the standard allowing this conversion.

Here:

[expr.reinterpret.cast]/11:

A glvalue of type T1, designating an object x, can be cast to the type “reference to T2” if an expression of type “pointer to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_­cast. The result is that of *reinterpret_­cast<T2 *>(p) where p is a pointer to x of type “pointer to T1”. ...

Since reinterpret_cast between pointers to object types (in your case, between pointers to pointers (to [member] functions)) is always allowed, it's also allowed in your case.

Sign up to request clarification or add additional context in comments.

1 Comment

Oh that was an obvious solution. I feel stupid for asking, but I suppose I should not delete an upvoted question. When I read that quote earlier, for some reason I thought that the member function pointer wasn't an object, but of course it is.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.