Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.17.6.75] |
|
Сообщ.
#1
,
|
|
|
Всем привет.
Возник у нас на работе очередной раз вопрос о properties в с++. Я быстренько накидал кодину enum class PropertyType { ReadOnly, WriteOnly }; template <class Getter, Getter getter> struct PropertyGetterTraits; template <> struct PropertyGetterTraits<PropertyType, PropertyType::WriteOnly> { using Owner = void; using Type = void; static constexpr bool needGetter = false; }; template <class C, class R, R(C::*Getter)()> struct PropertyGetterTraits<R(C::*)(), Getter> { static constexpr bool needGetter = true; using Owner = C; using Type = R; static R get(C* c) { return (c->*Getter)(); } }; template <class C, class R, R(C::*Getter)()const> struct PropertyGetterTraits<R(C::*)()const, Getter> { static constexpr bool needGetter = true; using Owner = C; using Type = R; static R get(C* c) { return (c->*Getter)(); } }; template <class C, class R, R(C::*Member)> struct PropertyGetterTraits<R(C::*), Member> { static constexpr bool needGetter = true; using Owner = C; using Type = R; static R get(C* c) { return (c->*Member); } }; template <class Setter, Setter setter> struct PropertySetterTraits; template <> struct PropertySetterTraits<PropertyType, PropertyType::ReadOnly> { using Owner = void; using Type = void; static constexpr bool needSetter = false; }; template <class C, class R, void(C::*Setter)(const R&)> struct PropertySetterTraits<void(C::*)(const R&), Setter> { static constexpr bool needSetter = true; using Owner = C; using Type = R; template <class U> static void set(C* c, U&& nv) { return (c->*Setter)(std::forward<U>(nv)); } }; template <class C, class R, void(C::*Setter)(R)> struct PropertySetterTraits<void(C::*)(R), Setter> { static constexpr bool needSetter = true; using Owner = C; using Type = R; template <class U> static void set(C* c, U&& nv) { return (c->*Setter)(std::forward<U>(nv)); } }; template <class C, class R, R(C::*Member)> struct PropertySetterTraits<R(C::*), Member> { static constexpr bool needSetter = true; using Owner = C; using Type = R; template <class U> static R set(C* c, U&& nv) { return (c->*Member) = std::forward<U>(nv); } }; template <class Getter, Getter getter, class Setter, Setter setter> class Property { using GTraits = PropertyGetterTraits<Getter, getter>; using STraits = PropertySetterTraits<Setter, setter>; static_assert(GTraits::needGetter || STraits::needSetter, "property could not be read only and write only in same time"); static_assert(GTraits::needGetter && STraits::needSetter && ( std::is_same<typename GTraits::Owner, typename STraits::Owner>::value && std::is_same<typename GTraits::Type, typename STraits::Type>::value) || std::true_type::value, "both getter and setter should be the same type and same owner"); public: static constexpr bool needSetter = STraits::needSetter; static constexpr bool needGetter = GTraits::needGetter; public: using Type = std::conditional_t<GTraits::needGetter, typename GTraits::Type, typename STraits::Type>; using Owner = std::conditional_t<GTraits::needGetter, typename GTraits::Owner, typename STraits::Owner>; public: Property(Owner* owner) : owner_(owner) { } Property(const Property&) = delete; void operator=(const Property&) = delete; Property(Property&&) = delete; void operator=(Property&&) = delete; public: template <class U, class = std::enable_if_t<needSetter && needGetter && std::is_convertible<U, Type>::value>> Type operator=(U&& newValue) { STraits::set(owner_, std::forward<U>(newValue)); return GTraits::get(owner_); } template <class U, class = std::enable_if_t<needSetter && !needGetter && std::is_convertible<U, Type>::value>> void operator=(U&& newValue) { STraits::set(owner_, std::forward<U>(newValue)); } template <class U, class = std::enable_if_t<needGetter && std::is_convertible<U, Type>::value>> bool operator==(const U& u) const { return GTraits::get(owner_) == u; } template <class U, class = std::enable_if_t<needGetter && std::is_convertible<Type, U>::value>> operator U() const { return GTraits::get(owner_); } private: Owner* owner_; }; template <class Lhr, class Rhr1, Rhr1 rhr1, class Rhr2, Rhr2 rhr2> bool operator==(const Lhr& lhr, const Property<Rhr1, rhr1, Rhr2, rhr2>& prop) { static_assert(Property<Rhr1, rhr1, Rhr2, rhr2>::needGetter, "property not gettable"); return prop == lhr; } #define PW(x) decltype(x), x class PropertyTest { private: int x_; double y_; std::string z_; public: double getY() const { return y_ * 100.0; } void setY(double nY) { y_ = nY / 100.0; } void updateZ(int zz) { z_ = std::to_string(zz); } public: PropertyTest() : x_(0) , y_(0) , z_("0") , x(this) , y(this) , z(this) , newZ(this) { } PropertyTest(const PropertyTest& pt) : x_(pt.x_) , y_(pt.y_) , z_(pt.z_) , x(this) , y(this) , z(this) , newZ(this) { } public: Property<PW(&PropertyTest::x_), PW(&PropertyTest::x_)> x; Property<PW(&PropertyTest::getY), PW(&PropertyTest::setY)> y; Property<PW(&PropertyTest::z_), PW(PropertyType::ReadOnly)> z; Property<PW(PropertyType::WriteOnly), PW(&PropertyTest::updateZ)> newZ; }; TEST(PropertyTest, FirstRun) { PropertyTest pt; ASSERT_EQ(0, pt.x); ASSERT_EQ(0.0, pt.y); ASSERT_EQ("0", pt.z); pt.x = 10; pt.y = 100.0; pt.newZ = 15; ASSERT_EQ(10, pt.x); ASSERT_EQ(100.0, pt.y); ASSERT_EQ("15", pt.z); int a = pt.x; auto pt2 = pt; ASSERT_EQ(10, pt2.x); ASSERT_EQ(100.0, pt2.y); ASSERT_EQ("15", pt2.z); } По мимо прочих проблем, тут есть КМК основная проблема, что класс который захочет использовать проперти, сразу же лишается возможности использовать дефолтные конструкторы и дефолтные operator= всех мастей. Ну во общем это пред история. К вопросу имеющая посредственное отношение. Прошу к пропертям сильно не цепляться. Вопрос такой. У Property есть this и указатель на мембер или метод основного класс. И возникла безумная идея - может можно как-то знаю эти два указателя узнать указатель на основной класс. Возможно для этого потребуется еще указатель как на мембер на само проперти? Я никогда так глубоко не лазил, по этому даже идеи нет в какую сторону копать. Есть идеи? |