C++でPropertyつづき1


self()呼び出しもできた。http://codepad.org/eKAdqttP
以下に同じコードを

#include <boost/typeof/typeof.hpp>
#include <iostream>

template<typename T>
struct property_get_type;

template<typename ReturnType,typename Class>
struct property_get_type<ReturnType (Class::*)() const>
{
  typedef ReturnType type;
};

template<typename T>
struct property_set_type;

template<typename ReturnType,typename Class,typename Argument>
struct property_set_type<ReturnType (Class::*)(Argument)>
{
  typedef Argument type;
};

template <class Signature>
class signature
{
  typedef BOOST_TYPEOF_TPL(&Signature::get) get_signature_type;
  typedef BOOST_TYPEOF_TPL(&Signature::set) set_signature_type;
public:
  typedef typename property_get_type<get_signature_type>::type get_return_type;
  typedef typename property_set_type<set_signature_type>::type set_argument_type;
};

template <class Class>
struct get_derived
{
  virtual const Class* self() const { return 0; }
};

#define MY_PROPERTY(Property, Class, Name) \
  struct Property##_##Class : public signature<Property<get_derived<Class> > >, public Property<get_derived<Class> >\
  {\
    typedef Property<get_derived<Class> > base_type;\
    get_return_type get() const { return static_cast<const base_type*>(this)->get(); }\
    void set(set_argument_type v) { static_cast<base_type*>(this)->set(v); }\
    const Class* self() const { return reinterpret_cast<Class*>(size_t(this)-offset()); }\
    size_t offset() const {\
      union {\
        Class* class_pointer;\
        size_t rep;\
      } c;\
      c.rep=0;\
      return size_t(&c.class_pointer->Name);\
    }\
    Property##_##Class & operator=(set_argument_type v) { set(v); return *this; }\
    operator get_return_type () const { return get(); }\
  }  Name

class my_class
{
  template <class Base>
  struct my_property : Base
  {
    double get() const { return arg_; }
    void set(double v) {
      arg_ = v; 
      this->self()->setter_info(); }
  private:
    double arg_;
  };
  void setter_info() const { std::cout << "call setter" << value << std::endl; }
public:
  MY_PROPERTY(my_property, my_class, value);
};

int main()
{
  my_class m;
  m.value = 5;
  double xx = m.value;
  return 0;
}

以下の関数内でvalueを出力するような処理を入れるとgetが永遠呼ばれてタイムアウトします・・・。

double get() const { return arg_; }

追記:
id:eldesh さんからtypoの指摘受けたので修正。
Boost.Propertyのほうはgetのみとかsetのみのにも対応するためにあんなに複雑になってるんだと分かりました。納得。

C++でPropertyつづき


前のエントリーに上書きしちゃったみたいです。汗



Boost.Propertyの実装案みたいなもの->http://codepad.org/A4vaAMPZ

これみて簡単にならないかやってみました。

#include <boost/typeof/typeof.hpp>
#include <iostream>

template<typename T>
struct property_get_type;

template<typename ReturnType,typename Class>
struct property_get_type<ReturnType (Class::*)() const>
{
  typedef ReturnType type;
};

template<typename T>
struct property_set_type;

template<typename ReturnType,typename Class,typename Argument>
struct property_set_type<ReturnType (Class::*)(Argument)>
{
  typedef Argument type;
};

template <class Signeture>
class signeture
{
  typedef BOOST_TYPEOF_TPL(&Signeture::get) get_signeture_type;
  typedef BOOST_TYPEOF_TPL(&Signeture::set) set_signeture_type;
public:
  typedef typename property_get_type<get_signeture_type>::type get_return_type;
  typedef typename property_set_type<set_signeture_type>::type set_argument_type;
};

#define MY_PROPERTY(Property, Class) \
  struct Property## _ ##Class : public signeture<Property>, public Property \
  { \
    typedef Property base_type; \
    get_return_type get() const { return static_cast<const base_type*>(this)->get(); } \
    void set(set_argument_type v) { static_cast<base_type*>(this)->set(v); } \
    Property## _ ##Class & operator=(set_argument_type v) { set(v); return *this; } \
    operator get_return_type () { return get(); } \
  }  \

class my_class
{
  struct my_property
  {
    double get() const { return arg_; }
    void set(double v) { arg_ = v; }
  private:
    double arg_;
  };
public:
  MY_PROPERTY(my_property, my_class) value;
};

int main()
{
  my_class m;
  m.value = 5;
  double xx = m.value;
  return 0;
}

self()で自分のポインタ取り出せなくなりました。orz
boost恐るべし・・・。