改めてプロパティーをC++で実現する方法を考えてみました。 clang ではメンバーのアドレス/オフセットが静的に扱えないので empty base optimization(EBO) で実現する形にしました。 型は分かれますが醜悪なマクロを使いません。
#include <iostream>
#include <type_traits>
#include <string>
template<class T>
struct PropertyUtil {
// empty base
PropertyUtil(const PropertyUtil&) = delete;
PropertyUtil(PropertyUtil&&) = delete;
PropertyUtil& operator=(const PropertyUtil&) = delete;
PropertyUtil& operator=(PropertyUtil&&) = delete;
protected:
PropertyUtil() {}
constexpr auto operator->() noexcept -> T* {
return reinterpret_cast<T*>(this);
}
constexpr auto operator->() const noexcept -> const T* {
return reinterpret_cast<const T*>(this);
}
};
template<typename T>
struct FooProperty {
// empty base
FooProperty() {}
FooProperty(const FooProperty&) {};
FooProperty(FooProperty&&) {};
FooProperty& operator=(const FooProperty&) {};
FooProperty& operator=(FooProperty&&) {};
[[no_unique_address]] struct : PropertyUtil<T> {
operator int() noexcept {
return this[0]->value_;
}
auto operator=(int n) noexcept -> int {
this[0]->value_ = n;
return n;
}
} value;
};
struct Dummy {};
static_assert(std::is_empty<FooProperty<Dummy>>::value);
struct Foo : FooProperty<Foo> {
private:
int value_ = 123;
friend struct FooProperty<Foo>;
friend int main();
};
int main()
{
auto a = Foo();
//auto _ = a;
std::cout << a.value << std::endl;
a.value = 256;
std::cout << a.value << std::endl;
}