Question

I have some code that looks like this:

char member_data[16];

template<typename T>
void set(void (T::*member)(void)) {
    memcpy(member_data, (char*) &member, sizeof(member));
}

template<typename T>
void (T::*)(void) get() {
    void (T::*member)(void);
    memcpy((char*) &member, member_data, sizeof(member));
    return member;
}

In the full context, I can be sure that set always uses the same type as the following get.

Can this be safely rewritten to use reinterpret_cast?

Edit:

Does this code do the same thing as above?

char member_data[16];

template<typename T>
using member_func = void (T::*)();

template<typename T>
void set(member_func<T> member) {
    reinterpret_cast<member_func<T>&>(member_data) = member;
}

template<typename T>
member_func<T> get() {
    return reinterpret_cast<member_func<T>&>(member_data));
}

Seems to work

Was it helpful?

Solution

The version you have in your edited part is not valid: you can't access an arbitrary char array as any other type. It may be possible to achieve something like this in a valid way by using std::aligned_storage<..> instead of a plain char array.

If member_data is declared as

std::aligned_storage<sizeof(member_func<T>), alignof(member_func<T>)>::type member_data;

or (essentially equivalently)

alignas(member_func<T>) char member_data[sizeof(member_func<T>)];

then your reinterpret_cast<..> approach should actually work. Instead of the template parameter dependent sizeof and alignof expressions, you can try using any fixed member_func<some_class>. It is highly unlikely that an implementation has different size or alignment requirements for pointers to member functions of different classes. If you want to be really safe use static asserts to check.

Can this be safely rewritten to use reinterpret_cast?

Other than what is described in your edit, you can directly cast a member function pointer, like reinterpret_cast<SomeType>(member), only, if SomeType is also a pointer-to-member type. So you can choose one pointer-to-member function type as "generic member function pointer storage", if all you do with that value is to convert it back to the original member pointer type.

You can't convert a pointer to member into a pointer to object (or vice versa).

In both cases your code is unsafe as is, because it will overrun the member_data buffer, if sizeof (void (T::*)()) > 16.

And by the way: the first code example already does use reinterpret_cast: The old-style cast to (char*) from void (T::**)() already is equivalent to a reinterpret_cast ;-)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top