Created
October 20, 2023 19:55
-
-
Save KaixoCode/2cd71e64441e1289fc30face8bd1a59d to your computer and use it in GitHub Desktop.
C++ public_cast
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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