Last active
May 14, 2023 17:06
-
-
Save m5knt/181e889f2fae995a506f1a8464c1e774 to your computer and use it in GitHub Desktop.
C++ Property (getter/setter/accessor) implement with anonymous-union-struct
This file contains 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
namespace property_impl { | |
/// property offset utillity | |
template <class Outer, bool IsStandardLayout = std::is_standard_layout<Outer>::value> | |
struct offset; | |
/// property offset utillity for standard-layout-class | |
template <class Outer> | |
struct offset<Outer, true> { | |
/// get offset | |
static constexpr auto get() noexcept -> std::size_t { | |
return offsetof(Outer, property_recognition0_); | |
} | |
}; | |
/// property offset utillity for not standard-layout-class | |
template <class Outer> | |
struct offset<Outer, false> { | |
/// get offset | |
static auto get() noexcept -> std::size_t { | |
return std::size_t(std::addressof(((Outer*)0)->property_recognition0_)); | |
} | |
}; | |
}; | |
/// for property offset utility, put on anonymous-union | |
#define PROPERTIES() \ | |
struct {} property_recognition0_ | |
#define PRIVATE_PROPERTY \ | |
friend property::outer_type; \ | |
private | |
#define PUBLIC_PROPERTY \ | |
friend property::outer_type; \ | |
public | |
/// base class for property implement | |
template <class Outer, class T = void> | |
class property { | |
public: | |
// future use ? | |
// class property : public using T { | |
// public: | |
// using auto = T; | |
// using sizeof = T; | |
// using value_type = T; | |
/// outer type | |
using outer_type = Outer; | |
/// union member only, require outer constructor | |
property() = delete; | |
// maybe useless stuff | |
property(property&&) = delete; | |
auto operator=(property&&) -> void = delete; | |
auto operator&() -> void = delete; | |
protected: | |
/// get outer pointer | |
auto outer() noexcept -> outer_type* { | |
return reinterpret_cast<outer_type*>(std::intptr_t(this) - property_impl::offset<outer_type>::get()); | |
} | |
/// get const outer pointer | |
auto outer() const noexcept -> const outer_type* { | |
return reinterpret_cast<const outer_type*>(std::intptr_t(this) - property_impl::offset<outer_type>::get()); | |
} | |
}; | |
class NotStandardLayout { | |
public: | |
union { | |
PROPERTIES(); | |
struct : property<NotStandardLayout> { | |
auto operator=(int n) noexcept -> int { | |
outer()->value_ = n; | |
return n; | |
} | |
auto operator()() noexcept -> int { | |
return outer()->value_; | |
} | |
} value; | |
}; | |
NotStandardLayout() { | |
} | |
private: | |
char value_ = 11; | |
}; | |
class StandardLayout { | |
public: | |
StandardLayout() {} | |
union { | |
PROPERTIES(); | |
struct : property<StandardLayout> { | |
auto operator=(int n) noexcept -> int { | |
outer()->value_ = n; | |
return n; | |
} | |
auto operator()() noexcept -> int { | |
return outer()->value_; | |
} | |
} value; | |
}; | |
char value_ = 22; | |
}; | |
int main() { | |
{ | |
NotStandardLayout f; | |
std::cout << typeid(property_impl::offset<decltype(f)>).name() << std::endl; | |
std::cout << f.value() << std::endl; | |
std::cout << (f.value = 99) << std::endl; | |
std::cout << f.value() << std::endl; | |
} | |
{ | |
StandardLayout f; | |
std::cout << typeid(property_impl::offset<decltype(f)>).name() << std::endl; | |
std::cout << f.value() << std::endl; | |
std::cout << (f.value = 99) << std::endl; | |
std::cout << f.value() << std::endl; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
We have considered a simpler implementation for C++20. This time It does not use macros.
https://gist.github.com/m5knt/0fcd120f1dc96631e7da4ba95f544d7c