Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> property в c++ 
:(
    Опции темы
Ivan.
Дата 18.8.2011, 19:15 (ссылка) |    (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



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

ЗАДАЧА:
Основная задача - это уйти от всяческих конструкторов, дополнительных переменных и максимально оптимизировать код на скорость, объем и удобство применения и вот что у меня получилось:
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;
}
//---------------------------------------------------------------------------


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

Это сообщение отредактировал(а) Ivan. - 24.8.2011, 16:36


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
boostcoder
Дата 18.8.2011, 19:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



инициатива не должна быть наказуема! поэтому держи пять 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;
}


PM WWW   Вверх
Ivan.
Дата 18.8.2011, 19:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



и что в нем не то? ну раскрыл ты дефайны, тебя это пугает? в итоге при компиляции это все сводится к нулю


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
boostcoder
Дата 18.8.2011, 19:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



меня ничего не пугает. смотрю и думаю...
PM WWW   Вверх
mes
Дата 18.8.2011, 20:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



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

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


Это сообщение отредактировал(а) mes - 18.8.2011, 20:04


--------------------
PM MAIL WWW   Вверх
Ivan.
Дата 18.8.2011, 20:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



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


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
Ivan.
Дата 19.8.2011, 08:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



Код

//---------------------------------------------------------------------------
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.

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


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
Alca
Дата 19.8.2011, 10:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 7
Всего: 50



А в бусте что нет пропертей?


--------------------
PM WWW ICQ Skype Jabber   Вверх
boostcoder
Дата 19.8.2011, 10:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



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

нет
PM WWW   Вверх
bsa
Дата 20.8.2011, 22:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Более того, в свое время Борланд пыталась их пропихнуть в стандарт. Но не приняли.
PM   Вверх
Ivan.
Дата 21.8.2011, 19:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



ни как не могу придумать реализацию проперти с индексом.
идея такая:
Код

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?

Это сообщение отредактировал(а) Ivan. - 21.8.2011, 19:19


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
mes
Дата 21.8.2011, 20:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



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

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

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




--------------------
PM MAIL WWW   Вверх
Ivan.
Дата 21.8.2011, 21:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



интересно, но это уже не проперти, если вместо [] придется использовать (), и все равно не получится реализовать сеттер


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
mes
Дата 21.8.2011, 21:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



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

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

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

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

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

Это сообщение отредактировал(а) mes - 21.8.2011, 21:24


--------------------
PM MAIL WWW   Вверх
Ivan.
Дата 22.8.2011, 11:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



придумал:
Код

#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];
}

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

Это сообщение отредактировал(а) Ivan. - 22.8.2011, 11:11


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
Alca
Дата 22.8.2011, 12:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 7
Всего: 50



Было бы неплохо убрать 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;


Это сообщение отредактировал(а) Alca - 22.8.2011, 12:09


--------------------
PM WWW ICQ Skype Jabber   Вверх
Ivan.
Дата 22.8.2011, 12:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



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

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

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


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
bsa
Дата 22.8.2011, 12:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



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

Размер указателя на метод класса может быть большего размера, чем указатель на данные.
PM   Вверх
Ivan.
Дата 22.8.2011, 13:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



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

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


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
Ivan.
Дата 22.8.2011, 13:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



вот что получилось на данный момент:
Код

#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 }
//---------------------------------------------------------------------------



--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
Ivan.
Дата 24.8.2011, 16:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



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

#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.

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

Это сообщение отредактировал(а) Ivan. - 24.8.2011, 17:07


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
mes
Дата 24.8.2011, 18:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



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

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



--------------------
PM MAIL WWW   Вверх
Ivan.
Дата 24.8.2011, 18:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



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

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


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
mes
Дата 24.8.2011, 19:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



что то типа :
Код

#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; }


Это сообщение отредактировал(а) mes - 24.8.2011, 19:37


--------------------
PM MAIL WWW   Вверх
Ivan.
Дата 25.8.2011, 10:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



ну то есть вынести в объявление блока пропертей - логично


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
Ivan.
Дата 25.8.2011, 11:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



обновленный вариант:
Код

#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];
}



--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
boostcoder
Дата 10.9.2011, 12:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



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

Добавлено через 5 минут и 15 секунд
думаю, что все же нужна возможность использовать проперти совместно с массивами но без гетера и сетера.
PM WWW   Вверх
boostcoder
Дата 10.9.2011, 12:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



при использовании type_traits и SFINAE, вместо макросов: PROPERTY_GS, PROPERTY_GW, PROPERTY_RS, PROPERTY_RW, PROPERTY_G, PROPERTY_R, PROPERTY_S, PROPERTY_W, PROPERTY_IGS, осталось бы всего два: PROPERTY_GET и PROPERTY_SET. которые были бы применимы как к членам-данным включая массивы, так и к сетерам/гетерам.

Это сообщение отредактировал(а) boostcoder - 10.9.2011, 12:35
PM WWW   Вверх
Ivan.
Дата 15.9.2011, 20:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



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


--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
Ivan.
Дата 16.9.2011, 08:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 291
Регистрация: 2.11.2004

Репутация: 1
Всего: 2



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

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

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



--------------------
Я могу ВСЁ, вопрос - сколько времени у меня это займет!
PM MAIL ICQ   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0836 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.