Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.60/5: Рейтинг темы: голосов - 5, средняя оценка - 4.60
0 / 0 / 2
Регистрация: 28.03.2014
Сообщений: 8
1

Шаблоны и функторы как callback для класса свойства объекта. Код работает - но не должен

14.09.2015, 15:39. Показов 948. Ответов 8
Метки нет (Все метки)

Здравствуйте!
Хочу написать реализацию класса свойства на шаблоне. Т.е есть объект, он инициирует необходимые проперти, в графическом представлении это может быть текстовое поле или combobox, при изменении которого вызывается необходимый функтор. Рабочий код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include "stdafx.h"
struct IsEnabled
{
    bool operator()(void) { return true;}
};
struct IsVisible
{
    bool operator()(void) { return true;}
};
template<typename ClassName, bool (ClassName::*enabler)()>
struct Enabler
{
    ClassName *m_sender;
    bool operator()(void) { return ((*m_sender).*enabler)();}
};
template<typename ClassName,typename Type, Type (ClassName::*getter)()>
struct Getter
{
    ClassName * m_sender;
    Type operator()(){ return ((*m_sender).*getter)();}
};
template<typename ClassName,typename Type,void (ClassName::*setter)(Type )>
struct Setter
{
    ClassName *m_sender;
    void operator ()(Type val)
    { 
        ((*m_sender).*setter)(val);
    }
    Type m_val;
};
template<typename GetterFunctor, typename SetterFunctor,typename EnableFunctor = IsEnabled, typename VisibleFunctor = IsVisible>
class CProperty
{
    
public:
    GetterFunctor m_getter;
    SetterFunctor m_setter;
    EnableFunctor m_enabler;
    VisibleFunctor m_visible;
    bool getValue()
    {
        return m_getter();
    }
    void setValue(bool  val)
    {
        m_setter(val);
    }
    bool isEnabled()
    {
        return m_enabler();
    }
    bool isVisible()
    {
        return m_visible();
    }
};
class test
{
public:
    test()
    {
    }
    void initProps()
    {
        CProperty<Getter<test,bool,&test::getVal>,Setter<test,bool,&test::setVal>,Enabler<test,&test::enabler>> prop;
        prop.getValue();
        prop.isEnabled();
        prop.isVisible();
        prop.setValue(false);
    }
    
    bool getVal()
    {
        return true;
    }
    void setVal(bool b)
    {
    }
    bool enabler()
    {
        return true;
    }
    bool visible()
    {
        return true;
    }
};
int _tmain(int argc, _TCHAR* argv[])
{
    test s;
    s.initProps();
    return 0;
}
Как видно свойство опрашивает заданный функтор - getter, setter и т.д, а использование функторов позволяет сделать не всегда необходимые методы проверки свойства - редактируемо, видимо - методами по дефолту. Но, этот код работает, хотя в каждом функторе в дебаге m_sender= 0xCCCCCC - память неинициализированна. Следовательно вызов в функторе, например, Setter - ((*m_sender).*setter)(val); должно приводить к падению. Оптимизация выключена в опциях компилятора. Почему работает?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
14.09.2015, 15:39
Ответы с готовыми решениями:

Метод класса не работает как callback-функция
Всем привет! Помогите разобраться с синтаксисом. Есть gui-прога, в которой содержится функция...

Libcurl: как должен выглядеть callback?
Прежде, чем юзать libcurl.dll пробовал PyCurl, но тот почему-то все время валит Python. В итоге...

Код работает не так как должен
Читаю я значит книгу, а там вот такой код: prompt = &quot;\nTell me something, and I will repeat it...

Этот код должен хранить «hellowor.d» как переменную под названием «Name», но она не работает
public static A = &quot;hello&quot;; public static B = &quot;wor.d&quot;; public static Name = A + B; Этот код...

__________________

Записывайтесь на профессиональные курсы C++ разработчиков
8
267 / 170 / 40
Регистрация: 25.08.2014
Сообщений: 1,087
Записей в блоге: 1
14.09.2015, 15:55 2
Цитата Сообщение от andrew_wk Посмотреть сообщение
Почему работает?
Потому что функции это не данные. Функция есть в файле? Всё что нужно для её вызова есть? Если ответ на оба вопроса утвердительный, то метод будет вызван. Фактически ты обращаешься к информации, получаемой из класса, а не объекта.
0
0 / 0 / 2
Регистрация: 28.03.2014
Сообщений: 8
14.09.2015, 16:03  [ТС] 3
Пока файл один. Что нужно для ее вызова - здесь немного недогоняю? Но мне кажется, я что-то не так делаю здесь - возможно нужно что-то подправить, чтобы небыло обращения по m_sender, который = 0xCCCCCC ? Можете подсказать?
0
Эксперт С++
8359 / 6097 / 610
Регистрация: 10.12.2010
Сообщений: 28,417
Записей в блоге: 30
14.09.2015, 16:55 4
Property ???

В языке C++ следует стараться использовать альтернативные приемы, поскольку данный паттерн не является естественным для языка и не может быть реализован полностью в соответствии со своей семантикой.
0
14120 / 7581 / 1802
Регистрация: 30.01.2014
Сообщений: 12,683
14.09.2015, 17:01 5
Цитата Сообщение от andrew_wk Посмотреть сообщение
Почему работает?
Потому что у тебя нет обращения к данным ClassName. Указатель this передается в холостую и фактически не используется.
Цитата Сообщение от andrew_wk Посмотреть сообщение
Но мне кажется, я что-то не так делаю здесь - возможно нужно что-то подправить, чтобы небыло обращения по m_sender, который = 0xCCCCCC ?
Конечно неправильно. Ты должен по крайней мере инициализировать m_sender в конструкторе.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
template<typename ClassName, bool (ClassName::*enabler)()>
struct Enabler
{
    ClassName *m_sender;
    bool operator()(void) { return ((*m_sender).*enabler)();}
 
    Enabler(ClassName * sender) : m_sender(sender) {}
};
template<typename ClassName,typename Type, Type (ClassName::*getter)()>
struct Getter
{
    ClassName * m_sender;
    Type operator()(){ return ((*m_sender).*getter)();}
    
    Getter(ClassName * sender) : m_sender(sender) {}
};
template<typename ClassName,typename Type,void (ClassName::*setter)(Type )>
struct Setter
{
    ClassName *m_sender;
    void operator ()(Type val)
    { 
        ((*m_sender).*setter)(val);
    }
    Type m_val;
 
    Setter(ClassName * sender) : m_sender(sender) {}
};
template<typename GetterFunctor, typename SetterFunctor,typename EnableFunctor = IsEnabled, typename VisibleFunctor = IsVisible>
class CProperty
{
    
public:
    GetterFunctor m_getter;
    SetterFunctor m_setter;
    EnableFunctor m_enabler;
    VisibleFunctor m_visible;
    template <typename T>
    CProperty(T * selfPtr) : m_getter(selfPtr), m_setter(selfPtr), m_enabler(selfPtr) 
    {}
 
    bool getValue()
    {
        return m_getter();
    }
    void setValue(bool  val)
    {
        m_setter(val);
    }
    bool isEnabled()
    {
        return m_enabler();
    }
    bool isVisible()
    {
        return m_visible();
    }
};
 
//.....................
 
    void initProps()
    {
        CProperty<Getter<test,bool,&test::getVal>,Setter<test,bool,&test::setVal>,Enabler<test,&test::enabler>> prop(this);
        prop.getValue();
        prop.isEnabled();
        prop.isVisible();
        prop.setValue(false);
    }
0
0 / 0 / 2
Регистрация: 28.03.2014
Сообщений: 8
14.09.2015, 17:35  [ТС] 6
Avazart - почти то что я хочу, но функторы позволят явно указывать setter'ы и getter'ы и не только. Меня вообще волнует именно возможность указать переменное число аргументов в
шаблоне.
DrOffset - спасибо! Да я в конструкторе CProperty пробовал инициировать функторы как m_getter(this) и компилятор падал при попытке собрать код.

А вообще, если смотреть взглядом опытного человека - моя реализация имеет право на существование ? Может быть есть "подводные камни", которые я не вижу?

Окончательный вариант:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "stdafx.h"
 
 
//Вызываются по-дефолту, если enabler и/или visible функтор не указаны 
template<typename ClassName>
struct IsEnabled
{
    ClassName *m_sender;
    IsEnabled(ClassName * name):m_sender(name){}
    bool operator()(void) { return true;}
};
 
template<typename ClassName>
struct IsVisible
{
    ClassName *m_sender;
    IsVisible(ClassName * name):m_sender(name){}
    bool operator()(void) { return true;}
};
 
 
template<typename ClassName, bool (ClassName::*enabler)()>
struct Enabler
{
    Enabler(ClassName * name){m_sender = name;}
    ClassName *m_sender;
    bool operator()(void) { return ((*m_sender).*enabler)();}
};
 
template<typename ClassName, bool (ClassName::*visible)()>
struct Visible
{
    Visible(ClassName * name):m_sender(name){}
    ClassName *m_sender;
    bool operator()(void) { return ((*m_sender).*visible)();}
};
 
 
template<typename ClassName,typename Type, Type (ClassName::*getter)()>
struct Getter
{
    Getter(ClassName * name):m_sender(name){}
    ClassName * m_sender;
    Type operator()(){ return ((*m_sender).*getter)();}
};
 
template<typename ClassName,typename Type,void (ClassName::*setter)(Type )>
struct Setter
{
    Setter(ClassName * name):m_sender(name){}
    ClassName *m_sender;
    void operator ()(Type val)
    { 
        ((*m_sender).*setter)(val);
    }
    Type m_val;
};
 
template<typename ClassName,typename GetterFunctor, typename SetterFunctor,typename EnableFunctor = IsEnabled<ClassName>, typename VisibleFunctor = IsVisible<ClassName>>
class CProperty
{
    
public:
    GetterFunctor m_getter;
    SetterFunctor m_setter;
    EnableFunctor m_enabler;
    VisibleFunctor m_visible;
 
    CProperty(ClassName  * obj):m_setter(obj),m_getter(obj),m_enabler(obj),m_visible(obj)
    {
    }
 
    bool getValue()
    {
        return m_getter();
    }
    void setValue(bool  val)
    {
        m_setter(val);
    }
 
    bool isEnabled()
    {
        return m_enabler();
    }
 
    bool isVisible()
    {
        return m_visible();
    }
};
 
 
 
class test
{
public:
 
    test()
    {
    }
    void initProps()
    {
        CProperty<test,Getter<test,bool,&test::getVal>,Setter<test,bool,&test::setVal>,Enabler<test,&test::enabler>,Visible<test,&test::visible>> *prop = new CProperty<test,Getter<test,bool,&test::getVal>,Setter<test,bool,&test::setVal>,Enabler<test,&test::enabler>,Visible<test,&test::visible>>(this);
        prop->getValue();
        prop->isEnabled();
        prop->isVisible();
        prop->setValue(false);
    }
    
    bool getVal()
    {
        return true;
    }
    void setVal(bool b)
    {
    }
    bool enabler()
    {
        return true;
    }
    bool visible()
    {
        return true;
    }
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    test s;
    s.initProps();
    return 0;
}
0
14120 / 7581 / 1802
Регистрация: 30.01.2014
Сообщений: 12,683
14.09.2015, 17:49 7
Цитата Сообщение от andrew_wk Посмотреть сообщение
моя реализация имеет право на существование ?
Да все имеет, пока в продакшен не идет
Ладно - это шутка.
Если серьезно, то предлагаю начать с вариантов использования твоего решения. Напиши себе примеры так, как будто все уже сделано, с точки зрения пользователя. Тогда подводные камни и неудобства сразу будут видны.
Для обучения эта задача вполне подойдет.
0
Эксперт С++
8359 / 6097 / 610
Регистрация: 10.12.2010
Сообщений: 28,417
Записей в блоге: 30
14.09.2015, 18:27 8
Цитата Сообщение от andrew_wk Посмотреть сообщение
Avazart - почти то что я хочу, но функторы позволят явно указывать setter'ы и getter'ы и не только. Меня вообще волнует именно возможность указать переменное число аргументов в
Нифига не понял из сказанного... каким тут боком функтуры?
0
267 / 170 / 40
Регистрация: 25.08.2014
Сообщений: 1,087
Записей в блоге: 1
14.09.2015, 19:08 9
Цитата Сообщение от andrew_wk Посмотреть сообщение
Пока файл один.
Исполняемый, я имел ввиду.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
14.09.2015, 19:08

Заказываю контрольные, курсовые, дипломные работы и диссертации здесь.

Производный класс Самоорганизующаяся таблица должен наследовать свойства и методы класса Таблица
класс таблица, содержащий целые числа Обьект класса таблица должен позволять: 1...

Как задать значение по умолчанию для свойства класса
Где и как можно сохранять и считывать значения свойств класса. Помню - такая возможность есть - но...

Как отменить свойства только для одной го элемента из класса?
http://rootedinisrael.org/ - создал для пунктов меню навигации нижнее подчеркивание при наведении,...

Один и тот же код на С++ и С#, Шаблоны, отображение содержимого шаблонного класса
написан на С++ шаблонный класс &quot;List&quot; созданный для создания списковой структуры внутри двоичного...

Callback как член класса
В общем, захотел я немного поработать с библиотекой libgit2. Эта библиотека предоставляет API...

Составить программу, которая определяет четыре объекта класса и выводит их на экран. Первый объект должен инициализироваться по умолчанию, второй ис
Составить программу, которая определяет четыре объекта класса и выводит их на экран. Первый...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.