Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > property в c++


Автор: Ivan. 18.8.2011, 19:15
Здравствуйте коллеги.
Уже несколько лет я возвращаюсь к мысли как же все таки реализовать проперти в сях. Все время упираюсь во всяческие ограничения компиляторов и т.п. и вот наконец решил, может не самый идеальный вариант, но все же не плохой.

ЗАДАЧА:
Основная задача - это уйти от всяческих конструкторов, дополнительных переменных и максимально оптимизировать код на скорость, объем и удобство применения и вот что у меня получилось:
1. Оптимизация - здесь все отлично, оптимизируется все на этапе компиляции и при работе ни чем не отличается от прямого доступа;
2. Применение - здесь тоже не плохо, можно прикреплять что угодно, хоть к полю родителя, хоть проперти на проперти, да хоть самого на себя зациклить можно;
3. Описание - здесь чуть похуже, но все равно не плохо: 
  а) необходимость прописать класс хозяина или мутатора.
  б) разные дефайны для описания нужного проперти.
  А в остальном не больше чем в настоящем __property;
4. Память - так как мой проперти является структурой, а многие компиляторы описывают пустую структуру минимум в один байт, то каждое проперти будет занимать по 1 байту. Эту проблему я решил описанием всех пропертей в union, то есть в худшем случаи все протепря займут в сумме 1 байт в классе;
5. Ну и наконец сама реализация - всего 15 строчек дефайнов.

КОД:
Код

//---------------------------------------------------------------------------
#define PROPERTY_BEGIN union { struct {} __PROP
#define PROPERTY_PARENT(TObj) (reinterpret_cast<TObj*>(reinterpret_cast<int>(this) - reinterpret_cast<int>(&(reinterpret_cast<TObj*>(1)->__PROP)) + 1))
#define PROPERTY_GET( TObj, TVal, Get)    inline      operator TVal()       {return Get(PROPERTY_PARENT(TObj));}
#define PROPERTY_READ(TObj, TVal, Field)  inline      operator TVal()       {return     PROPERTY_PARENT(TObj)->Field;}
#define PROPERTY_SET( TObj, TVal, Set)    inline TVal operator = (TVal Val) {return Set(PROPERTY_PARENT(TObj), Val);}
#define PROPERTY_WRITE(TObj, TVal, Field) inline TVal operator = (TVal Val) {return     PROPERTY_PARENT(TObj)->Field = Val;}
#define PROPERTY_GS(TObj, TVal, Get,  Set)   struct { PROPERTY_GET (TObj, TVal, Get)  PROPERTY_SET  (TObj, TVal, Set)   }
#define PROPERTY_GW(TObj, TVal, Get,  Write) struct { PROPERTY_GET (TObj, TVal, Get)  PROPERTY_WRITE(TObj, TVal, Write) }
#define PROPERTY_RS(TObj, TVal, Read, Set)   struct { PROPERTY_READ(TObj, TVal, Read) PROPERTY_SET  (TObj, TVal, Set)   }
#define PROPERTY_RW(TObj, TVal, Read, Write) struct { PROPERTY_READ(TObj, TVal, Read) PROPERTY_WRITE(TObj, TVal, Write) }
#define PROPERTY_G( TObj, TVal, Get)         struct { PROPERTY_GET (TObj, TVal, Get)                                    }
#define PROPERTY_R( TObj, TVal, Read)        struct { PROPERTY_READ(TObj, TVal, Read)                                   }
#define PROPERTY_S( TObj, TVal,       Set)   struct {                                 PROPERTY_SET  (TObj, TVal, Set)   }
#define PROPERTY_W( TObj, TVal,       Write) struct {                                 PROPERTY_WRITE(TObj, TVal, Write) }
#define PROPERTY_END }
//---------------------------------------------------------------------------


ОПИСАНИЕ:
PROPERTY_BEGIN - начало блока пропертей.
PROPERTY_END - конец блока пропертей.
Объявление проперти:
PROPERTY_GS - с getter-ом и setter-ом
PROPERTY_GW - с getter-ом и прямым доступом записи в поле
PROPERTY_RS - с прямым доступом чтения поля и setter-ом
PROPERTY_RW - с прямым доступом чтения поля и прямым доступом записи в поле
PROPERTY_G - только с getter-ом
PROPERTY_R - только с прямым доступом на чтение
PROPERTY_S - только с setter-ом
PROPERTY_W - только с прямым доступом на запись
остальные дефайны служебные

ПРИМЕР ПРИМЕНЕНИЯ:
Код

//---------------------------------------------------------------------------
class Tclass1 {
protected:
    int Ffoo;
public:
    PROPERTY_BEGIN;
        PROPERTY_RW(Tclass1, int, Ffoo, Ffoo) foo;
    PROPERTY_END;
};
class Tclass2 : public Tclass1 {
    int FVal;
    int FArray[2];
    static int GetVal(Tclass2* This)          {return This->FVal;}
    static int SetVal(Tclass2* This, int Val) {return This->FVal = Val;}
public:
    PROPERTY_BEGIN;
        PROPERTY_GS(Tclass2, int, GetVal, SetVal) Val1;
        PROPERTY_RW(Tclass2, int, FVal, FVal) Val2;
        PROPERTY_RS(Tclass2, int, foo, SetVal) Val3;
        PROPERTY_R(Tclass2, int, FArray[0]) Array0;
    PROPERTY_END;
} t;
//---------------------------------------------------------------------------
int main()
{
    t.foo = 1;
    t.Val1 = 10;
    t.Val2 = 20;
    t.Val3 = 30;
    PORTB = t.Val1;
    PORTB = t.Val2;
    PORTB = t.Val3;
    PORTB = t.foo;
    PORTB = t.Array0;
}
//---------------------------------------------------------------------------


ВЫВОДЫ:
Как видите привязаться можно к чему угодно, хоть к проперти родителя и оптимизируется на ура.
Если обнаружите ошибки или новые идеи - пишите.

Автор: boostcoder 18.8.2011, 19:35
инициатива не должна быть наказуема! поэтому держи пять smile

но давайте лучше посмотрим на препроцессированный код:
Код

class Tclass1 {
protected:
    int Ffoo;
public:

    union {

        struct {
        } __PROP;

        struct {

            inline operator int() {
                return (reinterpret_cast<Tclass1*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass1*> (1)->__PROP)) + 1))->Ffoo;
            }

            inline int operator =(int Val) {
                return (reinterpret_cast<Tclass1*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass1*> (1)->__PROP)) + 1))->Ffoo = Val;
            }
        } foo;
    };
};

class Tclass2 : public Tclass1 {
    int FVal;
    int FArray[2];

    static int GetVal(Tclass2* This) {
        return This->FVal;
    }

    static int SetVal(Tclass2* This, int Val) {
        return This->FVal = Val;
    }
public:

    union {

        struct {
        } __PROP;

        struct {

            inline operator int() {
                return GetVal((reinterpret_cast<Tclass2*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass2*> (1)->__PROP)) + 1)));
            }

            inline int operator =(int Val) {
                return SetVal((reinterpret_cast<Tclass2*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass2*> (1)->__PROP)) + 1)), Val);
            }
        } Val1;

        struct {

            inline operator int() {
                return (reinterpret_cast<Tclass2*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass2*> (1)->__PROP)) + 1))->FVal;
            }

            inline int operator =(int Val) {
                return (reinterpret_cast<Tclass2*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass2*> (1)->__PROP)) + 1))->FVal = Val;
            }
        } Val2;

        struct {

            inline operator int() {
                return (reinterpret_cast<Tclass2*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass2*> (1)->__PROP)) + 1))->foo;
            }

            inline int operator =(int Val) {
                return SetVal((reinterpret_cast<Tclass2*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass2*> (1)->__PROP)) + 1)), Val);
            }
        } Val3;

        struct {

            inline operator int() {
                return (reinterpret_cast<Tclass2*> (reinterpret_cast<int> (this) - reinterpret_cast<int> (&(reinterpret_cast<Tclass2*> (1)->__PROP)) + 1))->FArray[0];
            }
        } Array0;
    };
} t;

int main() {
    Tclass2 t;
    t.foo = 1;
    t.Val1 = 10;
    t.Val2 = 20;
    t.Val3 = 30;
    PORTB = t.Val1;
    PORTB = t.Val2;
    PORTB = t.Val3;
    PORTB = t.foo;
    PORTB = t.Array0;
}


Автор: Ivan. 18.8.2011, 19:41
и что в нем не то? ну раскрыл ты дефайны, тебя это пугает? в итоге при компиляции это все сводится к нулю

Автор: boostcoder 18.8.2011, 19:47
меня ничего не пугает. смотрю и думаю...

Автор: mes 18.8.2011, 20:04
Цитата(Ivan. @  18.8.2011,  18:15 Найти цитируемый пост)
Если обнаружите ошибки

что привлекло с беглого взгляда: попробуйте наследоваться от вашего класса с пропертями множественным наследованием, при этом Ваш класс должен быть не первым.. 

Автор: Ivan. 18.8.2011, 20:22
хотел проверить, но еще не успел. также нужно сделать проперти [] и закрыть операторы копии

Автор: Ivan. 19.8.2011, 08:56
Код

//---------------------------------------------------------------------------
class Tclass1 {
protected:
    volatile int Ffoo;
public:
    PROPERTY_BEGIN;
        PROPERTY_RW(Tclass1, int, Ffoo, Ffoo) foo1;
    PROPERTY_END;
};
//---------------------------------------------------------------------------
class Tclass2 {
protected:
    int Ffoo;
public:
    PROPERTY_BEGIN;
        PROPERTY_RW(Tclass2, int, Ffoo, Ffoo) foo2;
    PROPERTY_END;
};
//---------------------------------------------------------------------------
class Tclass3 : public Tclass1, public Tclass2 {
public:
    PROPERTY_BEGIN;
        PROPERTY_RW(Tclass3, int, foo1, foo1) Val1;
        PROPERTY_RW(Tclass3, int, foo2, foo2) Val2;
    PROPERTY_END;
} t;
//---------------------------------------------------------------------------
int main(){
    t.foo1 = 1;
    t.foo2 = 2;
    t.Val1 = 3;
    t.Val2 = 4;
}

Результат:
в Tclass1::Ffoo = 1 (так как переменная volatile)
в Tclass1::Ffoo = 3
в Tclass2::Ffoo = 4
Действие t.foo2 = 2; пропустил за ненадобностью, потому что оно тут же перекроется новыми значениями 4.

Вывод: с множественным наследованием работает прекрасно

Автор: Alca 19.8.2011, 10:40
А в бусте что нет пропертей?

Автор: boostcoder 19.8.2011, 10:47
Цитата(Alca @  19.8.2011,  10:40 Найти цитируемый пост)
в бусте что нет пропертей?

нет

Автор: bsa 20.8.2011, 22:09
Более того, в свое время Борланд пыталась их пропихнуть в стандарт. Но не приняли.

Автор: Ivan. 21.8.2011, 19:12
ни как не могу придумать реализацию проперти с индексом.
идея такая:
Код

class Tclass1 {
    int FVal[10];
    static int GetVal(Tclass1* This, int Index) {
        if ((unsigned)Index < (sizeof(FVal) / sizeof(FVal[0]) 
            return This->FVal[Index];
        throw ...;
    }
    struct {
        struct _T {
            inline operator int() {return Tclass1::GetVal(PROPERTY_PARENT(Tclass1), Index); 
        } _Val;
        inline _T& operator [](int Index) {return _Val;}
    } Val;
} t;
int main() {
    PORTB = t.Val[0];
}

остается вопрос, как передать Index?

Автор: mes 21.8.2011, 20:10
Цитата(Ivan. @  21.8.2011,  18:12 Найти цитируемый пост)
struct _T {
            inline operator int()

может так ?
Код

struct _T {
            inline int operator ()(int index) .. 


Автор: Ivan. 21.8.2011, 21:16
интересно, но это уже не проперти, если вместо [] придется использовать (), и все равно не получится реализовать сеттер

Автор: mes 21.8.2011, 21:17
Цитата(Ivan. @  21.8.2011,  20:16 Найти цитируемый пост)
 если вместо [] придется использовать () 

ну так поставьте оператор [] smile

Добавлено @ 21:20
Цитата(Ivan. @  21.8.2011,  20:16 Найти цитируемый пост)
и все равно не получится реализовать сеттер 

сейчас подумаю..

Добавлено @ 21:24
вам надо возвращать  не ссылку на _Val , а временный прокси-объект хранящий индекс в себе

Автор: Ivan. 22.8.2011, 11:01
придумал:
Код

#define PROPERTY_IGET(TVal, Get)    inline      operator TVal()       {return Get(Sender, Index);}
#define PROPERTY_ISET(TVal, Set)    inline TVal operator = (TVal Val) {return Set(Sender, Val, Index);}
#define PROPERTY_K(  TObj)          inline T&   operator [](int Index) {T t = {PROPERTY_PARENT(TObj), Index}; return t;}
#define PROPERTY_I(  TObj)                    struct T {TObj* Sender; int Index;
#define PROPERTY_IGS(TObj, TVal, Get,  Set)   struct { PROPERTY_I() PROPERTY_IGET (TVal, Get)  PROPERTY_ISET (TVal, Set)}; PROPERTY_K(TObj) }
class Tclass3 {
    int FArray[2];
    static int GetArray(Tclass3* This, int Index) {return This->FArray[Index];}
    static int SetArray(Tclass3* This, int Value, int Index) {return This->FArray[Index] = Value;}
public:
    PROPERTY_BEGIN;
        PROPERTY_IGS(Tclass3, int, GetArray, SetArray) Val3;
    PROPERTY_END;
} t;
int main() {
    t.Val3[1] = 10;
    PORTB = t.Val3[1];
}

раскрою дефайны, чтобы было понятней:
Код

class Tclass3 {
    int FArray[2];
    static int GetArray(Tclass3* This, int Index) {return This->FArray[Index];}
    static int SetArray(Tclass3* This, int Value, int Index) {return This->FArray[Index] = Value;}
public:
    union { struct {} __PROP;
        struct {
            struct T {
                Tclass3* Sender; int Index;
                inline     operator int()       {return GetArray(Sender, Index);}
                inline int operator = (int Val) {return SetArray(Sender, Val, Index);}
            };
            inline T& operator [](int Index) {T t = {PROPERTY_PARENT(Tclass3), Index}; return t;}
        } Val3;
    };
} t;
int main() {
    t.Val3[1] = 10;
    PORTB = t.Val3[1];
}

в итоге опять же все оптимизируется на этапе компиляции и ни чем не отличается от прямого вызова мутаторов.

Автор: Alca 22.8.2011, 12:09
Было бы неплохо убрать PROPERTY_BEGIN и PROPERTY_END:

Код

class Tclass3 {
    int FArray[2];
    static int GetArray(Tclass3* This, int Index) {return This->FArray[Index];}
    static int SetArray(Tclass3* This, int Value, int Index) {return This->FArray[Index] = Value;}
public:
        PROPERTY_IGS(Tclass3, int, GetArray, SetArray) Val3;
} t;

Автор: Ivan. 22.8.2011, 12:31
Цитата(Alca @  22.8.2011,  12:09 Найти цитируемый пост)
Было бы неплохо убрать PROPERTY_BEGIN и PROPERTY_END:

не получается по следующим причинам:
1. пустая структура во многих компиляторах равна 1 байту. (100 пропертей займет 100 байт в классе). для этого все проперти объединены в union.
2. нельзя получить относительный адрес объекта внутри объявления этого объекта. для этого в начало union-на помещена структура с именем __PROP, по которой определяется смещение родителя от проперти.

Добавлено через 1 минуту и 30 секунд
еще ни как не могу вспомнить флаг компилятора позволяющий преобразовывать указатель метода к void*, чтобы уйти от статических мутаторов

Автор: bsa 22.8.2011, 12:46
Цитата(Ivan. @  22.8.2011,  12:31 Найти цитируемый пост)
еще ни как не могу вспомнить флаг компилятора позволяющий преобразовывать указатель метода к void*

Размер указателя на метод класса может быть большего размера, чем указатель на данные.

Автор: Ivan. 22.8.2011, 13:06
Цитата(bsa @  22.8.2011,  12:46 Найти цитируемый пост)
Размер указателя на метод класса может быть большего размера, чем указатель на данные.

да, я понимаю. по этому такой флаг есть не во всех архитектурах. в билдере это не актуально, так как там есть настоящий проперти, в IAR_ARM указатель на метод равен 8 байтам, а вот в WIN_AVR такой флаг есть и указатель на метод равен указателю на данные.

Автор: Ivan. 22.8.2011, 13:52
вот что получилось на данный момент:
Код

#define PROPERTY_PARENT(TObj) (reinterpret_cast<TObj*>(reinterpret_cast<int>(this) - reinterpret_cast<int>(&(reinterpret_cast<TObj*>(1)->__PROP)) + 1))
#define PROPERTY_INDEX(TObj)                    inline T&    operator [](int Index){ T t = {PROPERTY_PARENT(TObj), Index}; return t;}
#define PROPERTY_GET(  TObj, TVal, Get)         inline       operator TVal()       { TObj* Sender = PROPERTY_PARENT(TObj); return Get(Sender);             }
#define PROPERTY_IGET( TObj, TVal, Get)         inline       operator TVal()       {                                       return Get(Sender, Index);      }
#define PROPERTY_READ( TObj, TVal, Field)       inline       operator TVal()       { TObj* Sender = PROPERTY_PARENT(TObj); return     Sender->Field;       }
#define PROPERTY_SET(  TObj, TVal,       Set)   inline TObj& operator = (TVal Val) { TObj* Sender = PROPERTY_PARENT(TObj);        Set(Sender, Val);        return *Sender; }
#define PROPERTY_ISET( TObj, TVal,       Set)   inline TObj& operator = (TVal Val) {                                              Set(Sender, Val, Index); return *Sender; }
#define PROPERTY_WRITE(TObj, TVal,       Field) inline TObj& operator = (TVal Val) { TObj* Sender = PROPERTY_PARENT(TObj);            Sender->Field = Val; return *Sender; }
//---------------------------------------------------------------------------
#define PROPERTY_GS(   TObj, TVal, Get,  Set)   struct { PROPERTY_GET  (TObj, TVal, Get)  PROPERTY_SET  (TObj, TVal, Set)   }
#define PROPERTY_GW(   TObj, TVal, Get,  Write) struct { PROPERTY_GET  (TObj, TVal, Get)  PROPERTY_WRITE(TObj, TVal, Write) }
#define PROPERTY_RS(   TObj, TVal, Read, Set)   struct { PROPERTY_READ (TObj, TVal, Read) PROPERTY_SET  (TObj, TVal, Set)   }
#define PROPERTY_RW(   TObj, TVal, Read, Write) struct { PROPERTY_READ (TObj, TVal, Read) PROPERTY_WRITE(TObj, TVal, Write) }
#define PROPERTY_G(    TObj, TVal, Get)         struct { PROPERTY_GET  (TObj, TVal, Get)                                    }
#define PROPERTY_R(    TObj, TVal, Read)        struct { PROPERTY_READ (TObj, TVal, Read)                                   }
#define PROPERTY_S(    TObj, TVal,       Set)   struct {                                  PROPERTY_SET  (TObj, TVal, Set)   }
#define PROPERTY_W(    TObj, TVal,       Write) struct {                                  PROPERTY_WRITE(TObj, TVal, Write) }
#define PROPERTY_IGS(  TObj, TVal, Get,  Set)   struct { struct T {TObj* Sender; int Index; PROPERTY_IGET (TObj, TVal, Get)  PROPERTY_ISET (TObj, TVal, Set)}; PROPERTY_INDEX(TObj) }
#define PROPERTY_BEGIN union { struct {} __PROP
#define PROPERTY_END }
//---------------------------------------------------------------------------

Автор: Ivan. 24.8.2011, 16:58
Выяснилось, что описывать статические мутаторы не нужно. видимо когда я пытался решить эту задачу через темплейты я уперся в это ограничение и подумал, что это засада, а при реализации через дефайны в этом необходимость отпала.
ИТОГО все свелось к следующему:
Код

#ifndef PropertyH
#define PropertyH
//---------------------------------------------------------------------------
#define PROPERTY_PARENT(TObj) (reinterpret_cast<TObj*>(reinterpret_cast<int>(this) - reinterpret_cast<int>(&(reinterpret_cast<TObj*>(1)->__PROP)) + 1))
#define PROPERTY_INDEX(TObj)                    inline T     operator [](int Index){ T t = {PROPERTY_PARENT(TObj), Index}; return t;}
#define PROPERTY_GET(  TObj, TVal, Get)         inline       operator TVal()       { TObj* Sender = PROPERTY_PARENT(TObj); return Sender->Get();           }
#define PROPERTY_IGET( TObj, TVal, Get)         inline       operator TVal()       {                                       return Sender->Get(Index);      }
#define PROPERTY_READ( TObj, TVal, Field)       inline       operator TVal()       { TObj* Sender = PROPERTY_PARENT(TObj); return Sender->Field;           }
#define PROPERTY_SET(  TObj, TVal,       Set)   inline TObj& operator = (TVal Val) { TObj* Sender = PROPERTY_PARENT(TObj);        Sender->Set(Val);        return *Sender; }
#define PROPERTY_ISET( TObj, TVal,       Set)   inline TObj& operator = (TVal Val) {                                              Sender->Set(Val, Index); return *Sender; }
#define PROPERTY_WRITE(TObj, TVal,       Field) inline TObj& operator = (TVal Val) { TObj* Sender = PROPERTY_PARENT(TObj);        Sender->Field = Val;     return *Sender; }
//---------------------------------------------------------------------------
#define PROPERTY_GS(   TObj, TVal, Get,  Set)   struct { PROPERTY_GET  (TObj, TVal, Get)  PROPERTY_SET  (TObj, TVal, Set)   }
#define PROPERTY_GW(   TObj, TVal, Get,  Write) struct { PROPERTY_GET  (TObj, TVal, Get)  PROPERTY_WRITE(TObj, TVal, Write) }
#define PROPERTY_RS(   TObj, TVal, Read, Set)   struct { PROPERTY_READ (TObj, TVal, Read) PROPERTY_SET  (TObj, TVal, Set)   }
#define PROPERTY_RW(   TObj, TVal, Read, Write) struct { PROPERTY_READ (TObj, TVal, Read) PROPERTY_WRITE(TObj, TVal, Write) }
#define PROPERTY_G(    TObj, TVal, Get)         struct { PROPERTY_GET  (TObj, TVal, Get)                                    }
#define PROPERTY_R(    TObj, TVal, Read)        struct { PROPERTY_READ (TObj, TVal, Read)                                   }
#define PROPERTY_S(    TObj, TVal,       Set)   struct {                                  PROPERTY_SET  (TObj, TVal, Set)   }
#define PROPERTY_W(    TObj, TVal,       Write) struct {                                  PROPERTY_WRITE(TObj, TVal, Write) }
#define PROPERTY_IGS(  TObj, TVal, Get,  Set)   struct { struct T {TObj* Sender; int Index; PROPERTY_IGET (TObj, TVal, Get) PROPERTY_ISET (TObj, TVal, Set)}; PROPERTY_INDEX(TObj) }
//---------------------------------------------------------------------------
#define PROPERTY_BEGIN union { struct {} __PROP
#define PROPERTY_END }
//---------------------------------------------------------------------------
#endif

Примет:
Код

class Tclass1 {
    int FVal;
    int FArray[10];
    void SetVal(int Val) {FVal = Val;}
    int GetVal() {return FVal;}
    void SetArray(int Val, int Index) {if ((unsigned)Index < sizeof(FArray) / sizeof(FArray[0])) FArray[Index] = Val;}
    int GetArray(int Index) {if ((unsigned)Index < sizeof(FArray) / sizeof(FArray[0])) return FArray[Index]; return 0;}
public:
    PROPERTY_BEGIN;
        PROPERTY_RS(Tclass1, int, FVal, SetVal) Val1;
        PROPERTY_GW(Tclass1, int, GetVal, FVal) Val2;
        PROPERTY_RW(Tclass1, int, FVal, FVal) Val3;
        PROPERTY_IGS(Tclass1, int, GetArray, SetArray) Array;
    PROPERTY_END;
} t;
//---------------------------------------------------------------------------
int main(){
    t.Val1 = 1;
    t.Val2 = t.Val1;
    t.Array[10] = t.Val3;
    PORTB = t.Array[10];
}
//---------------------------------------------------------------------------

При рассмотрении ассемблера:
В поле t.FVal помещено значение 1;
Действие t.Val2 = t.Val1; было проигнорировано, так как это копирование самого себя, а переменная не является volatile;
Действие t.Array[10] = t.Val3; было проигнорировано, так как Index лежит за пределами массива FArray;
В PORTB выдан 0, так как по условию, если Index лежит за пределами массива - getter возвращает 0.

Остались следующие неудобства:
- необходимость описывать блок пропертей;
- разные дефайны для описания разных пропертей;
- и необходимость описывать название класса хозяина проперти.

Автор: mes 24.8.2011, 18:19
Цитата(Ivan. @  24.8.2011,  15:58 Найти цитируемый пост)
- и необходимость описывать название класса хозяина проперти.

а что заменить это внутренним тайпдефом разве не получается ?

Автор: Ivan. 24.8.2011, 18:54
Цитата(mes @  24.8.2011,  18:19 Найти цитируемый пост)
а что заменить это внутренним тайпдефом разве не получается ?

приведи пример пожалуйста. что то в голову ничего не идет

Автор: mes 24.8.2011, 19:36
что то типа :
Код

#define PROPERTY_BEGIN(T) union { typedef T Hander; struct {} __PROP
#define PROPERTY_PARENT (reinterpret_cast<Handler*>(reinterpret_cast<int>(this) -...
#define PROPERTY_SET(TVal,       Set)   inline Handler& operator = (TVal Val) { Handler* Sender = PROPERTY_PARENT;        Sender->Set(Val);        return *Sender; }

Автор: Ivan. 25.8.2011, 10:20
ну то есть вынести в объявление блока пропертей - логично

Автор: Ivan. 25.8.2011, 11:29
обновленный вариант:
Код

#ifndef PropertyH
#define PropertyH
//---------------------------------------------------------------------------
#define PROPERTY_PARENT (reinterpret_cast<TObj*>(reinterpret_cast<int>(this) - reinterpret_cast<int>(&(reinterpret_cast<TObj*>(1)->__PROP)) + 1))
#define PROPERTY_INDEX                    inline T     operator [](int Index){ T t = {PROPERTY_PARENT, Index}; return t;}
#define PROPERTY_GET(  TVal, Get)         inline       operator TVal()       { TObj* Sender = PROPERTY_PARENT; return Sender->Get();           }
#define PROPERTY_IGET( TVal, Get)         inline       operator TVal()       {                                 return Sender->Get(Index);      }
#define PROPERTY_READ( TVal, Field)       inline       operator TVal()       { TObj* Sender = PROPERTY_PARENT; return Sender->Field;           }
#define PROPERTY_SET(  TVal,       Set)   inline TObj& operator = (TVal Val) { TObj* Sender = PROPERTY_PARENT;        Sender->Set(Val);        return *Sender; }
#define PROPERTY_ISET( TVal,       Set)   inline TObj& operator = (TVal Val) {                                        Sender->Set(Val, Index); return *Sender; }
#define PROPERTY_WRITE(TVal,       Field) inline TObj& operator = (TVal Val) { TObj* Sender = PROPERTY_PARENT;        Sender->Field = Val;     return *Sender; }
//---------------------------------------------------------------------------
#define PROPERTY_GS(   TVal, Get,  Set)   struct { PROPERTY_GET (TVal, Get)  PROPERTY_SET  (TVal, Set)   }
#define PROPERTY_GW(   TVal, Get,  Write) struct { PROPERTY_GET (TVal, Get)  PROPERTY_WRITE(TVal, Write) }
#define PROPERTY_RS(   TVal, Read, Set)   struct { PROPERTY_READ(TVal, Read) PROPERTY_SET  (TVal, Set)   }
#define PROPERTY_RW(   TVal, Read, Write) struct { PROPERTY_READ(TVal, Read) PROPERTY_WRITE(TVal, Write) }
#define PROPERTY_G(    TVal, Get)         struct { PROPERTY_GET (TVal, Get)                              }
#define PROPERTY_R(    TVal, Read)        struct { PROPERTY_READ(TVal, Read)                             }
#define PROPERTY_S(    TVal,       Set)   struct {                           PROPERTY_SET  (TVal, Set)   }
#define PROPERTY_W(    TVal,       Write) struct {                           PROPERTY_WRITE(TVal, Write) }
#define PROPERTY_IGS(  TVal, Get,  Set)   struct { struct T {TObj* Sender; int Index; PROPERTY_IGET (TVal, Get) PROPERTY_ISET (TVal, Set)}; PROPERTY_INDEX }
//---------------------------------------------------------------------------
#define PROPERTY_BEGIN(TParent) typedef TParent TObj; union { struct {} __PROP
#define PROPERTY_END }
//---------------------------------------------------------------------------
#endif

пример:
Код

class Tclass1 {
    int FVal;
    int FArray[10];
    void SetVal(int Val) {FVal = Val;}
    int GetVal() {return FVal;}
    void SetArray(int Val, int Index) {if ((unsigned)Index < sizeof(FArray) / sizeof(FArray[0])) FArray[Index] = Val;}
    int GetArray(int Index) {if ((unsigned)Index < sizeof(FArray) / sizeof(FArray[0])) return FArray[Index]; return 0;}
public:
    PROPERTY_BEGIN(Tclass1);
        PROPERTY_RS(int, FVal, SetVal) Val1;
        PROPERTY_GW(int, GetVal, FVal) Val2;
        PROPERTY_RW(int, FVal, FVal) Val3;
        PROPERTY_IGS(int, GetArray, SetArray) Array;
    PROPERTY_END;
} t;
//---------------------------------------------------------------------------
int main(){
    t.Val1 = 1;
    t.Val2 = t.Val1;
    t.Array[10] = t.Val3;
    PORTB = t.Array[10];
}

Автор: boostcoder 10.9.2011, 12:00
Ivan., я так понял, что при использовании проперти совместно с массивами, без гетера и сетера не обойтись?

Добавлено через 5 минут и 15 секунд
думаю, что все же нужна возможность использовать проперти совместно с массивами но без гетера и сетера.

Автор: boostcoder 10.9.2011, 12:34
при использовании http://www.boost.org/doc/libs/1_47_0/libs/type_traits/index.html и http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error, вместо макросов: PROPERTY_GS, PROPERTY_GW, PROPERTY_RS, PROPERTY_RW, PROPERTY_G, PROPERTY_R, PROPERTY_S, PROPERTY_W, PROPERTY_IGS, осталось бы всего два: PROPERTY_GET и PROPERTY_SET. которые были бы применимы как к членам-данным включая массивы, так и к сетерам/гетерам.

Автор: Ivan. 15.9.2011, 20:29
я долго пытался решить эту задачу с помощью template, я бы даже сказал, не один год.
вот так вот спишь ночью и вдруг приходит сонная мысль - "вот же оно решение!, в теории все должно работать". просыпаешься, начинаешь реализовывать и опять та же самая непреодолимая стена.
дело в том, что определение смещения поля от корня класса:
Код
(reinterpret_cast<TObj*>(reinterpret_cast<int>(this) - reinterpret_cast<int>(&(reinterpret_cast<TObj*>(1)->__PROP)) + 1))
не является константой и его нельзя применить как параметр template. в define оно хорошо применяется, ну и что, что не константа, компилятор все ровно ее с оптимизирует на этапе компиляции.

Автор: Ivan. 16.9.2011, 08:33
Цитата(boostcoder @  10.9.2011,  12:00 Найти цитируемый пост)
Ivan., я так понял, что при использовании проперти совместно с массивами, без гетера и сетера не обойтись? думаю, что все же нужна возможность использовать проперти совместно с массивами но без гетера и сетера.

да вроде бы есть уже:
Код
PROPERTY_R(int*, FArray) Array;
вот тебе и указатель на массив, а дальше бери от него [].
вот с сочетанием [геттера или сеттера] и прямого обращения - тут немного сложнее.

Добавлено через 6 минут и 47 секунд
даже я бы сказал, что лучше вот так:
Код
PROPERTY_R(int* const, FArray) Array;

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)