Skip to content

Instantly share code, notes, and snippets.

@m5knt
Last active May 14, 2023 17:06
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save m5knt/181e889f2fae995a506f1a8464c1e774 to your computer and use it in GitHub Desktop.
Save m5knt/181e889f2fae995a506f1a8464c1e774 to your computer and use it in GitHub Desktop.
C++ Property (getter/setter/accessor) implement with anonymous-union-struct
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;
}
}
@m5knt
Copy link
Author

m5knt commented Dec 27, 2022

We have considered a simpler implementation for C++20. This time It does not use macros.
https://gist.github.com/m5knt/0fcd120f1dc96631e7da4ba95f544d7c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment