Skip to content

Instantly share code, notes, and snippets.

@KaixoCode
Created October 20, 2023 19:55
Show Gist options
  • Save KaixoCode/2cd71e64441e1289fc30face8bd1a59d to your computer and use it in GitHub Desktop.
Save KaixoCode/2cd71e64441e1289fc30face8bd1a59d to your computer and use it in GitHub Desktop.
C++ public_cast
/**
* Sneaky public cast, implemented using the auto-return type friend
* function trick to have a stateful compiler. This links the value
* of a private pointer-to-member to a class. This code even works
* at compile-time. Although in Visual Studio, Intellisense seems
* to have trouble some trouble.
*
* Do note that you cannot use this public_cast function for a specific
* member above the `template<> link` specialization. This is because
* we're relying on compiler state, and it reads the file top-down.
*/
namespace detail {
template<class Key>
struct member_tag {
// Declares the auto-return friend function, at this point
// this function does not have a return type yet.
friend constexpr auto link_member(member_tag<Key>);
};
template<class Key, auto M>
struct define_link {
constexpr static bool value = true;
// Only at this point does this function get a return type.
// And because a function signature cannot be distinguished
// by return type alone, from now on this function's return
// type will always be the type of M.
friend constexpr auto link_member(member_tag<Key>) { return M; };
};
}
// This defines a link between the Key and the value M using
template<class Key, auto M> requires detail::define_link<Key, M>::value
struct link;
template<class Key, class Ty>
constexpr auto& public_cast(Ty& v) {
// Here we invoke the function using the member tag, and because
// we gave this function a body in `define_link`, it will now return
// our private member pointer without actually needing to specify its
// type or value.
return v.*(link_member(detail::member_tag<Key>{}));
};
// ------------------------------------------------
class A {
int a = 42;
};
template<> struct link<struct A_a, &A::a>;
int main() {
A a{};
int& v = public_cast<A_a>(a);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment