На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Получить указатель на структуру из структуры мембера
    Всем привет.
    Возник у нас на работе очередной раз вопрос о properties в с++.
    Я быстренько накидал кодину
    ExpandedWrap disabled
      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 и указатель на мембер или метод основного класс. И возникла безумная идея - может можно как-то знаю эти два указателя узнать указатель на основной класс. Возможно для этого потребуется еще указатель как на мембер на само проперти? Я никогда так глубоко не лазил, по этому даже идеи нет в какую сторону копать. Есть идеи?
    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
    0 пользователей:


    Рейтинг@Mail.ru
    [ Script execution time: 0,0260 ]   [ 17 queries used ]   [ Generated: 20.04.24, 03:27 GMT ]