Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

C++

Войти
Регистрация
Восстановить пароль
 
Archi0
28 / 14 / 4
Регистрация: 18.07.2013
Сообщений: 169
#1

Чем _Get_pointer_type отличается от обычного получения типа указателя - C++

29.10.2015, 07:52. Просмотров 358. Ответов 6
Метки нет (Все метки)

При попытке более детально понять работу стандартных контейнеров в STD столкнулся с немалым количеством головоломок. вот одна из них.
C++
1
typedef typename _Get_pointer_type<_Alloc>::type pointer;
переходим к объявлению

C++
1
2
3
template<class _Ty>
    struct _Get_pointer_type
    _GET_TYPE_OR_DEFAULT(pointer, typename _Ty::value_type *);
Читаем макрос

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#define _GET_TYPE_OR_DEFAULT(TYPE, DEFAULT) \
    { \
    template<class _Uty> \
        static auto _Fn(int) \
            -> _Identity<typename _Uty::TYPE>; \
 \
    template<class _Uty> \
        static auto _Fn(_Wrap_int) \
            -> _Identity<DEFAULT>; \
 \
    typedef decltype(_Fn<_Ty>(0)) _Decltype; \
    typedef typename _Decltype::type type; \
    }
Возникает вопрос, а чем этот код отличается от обычного получения типа указателя. Я разгадал этот ребус.

следующий код показал

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
template <class _Ty>
class Get_pointer
{
public:
    typedef _Ty* pointer;
};
 
template <class _Ty>
class Probationer
{
public:
    typedef _Ty value_type;
    typedef _Ty pointer;
};
 
template <class _Ty>
class Probationer2
{
public:
    typedef _Ty value_type;
};
 
int func0(int, int)
{
    return 0;
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    auto x = func0;
    Get_pointer < int (*) (int,int) >::pointer vb =  &x;
    std::_Get_pointer_type< Probationer<int (*) (int,int)> >::type g = func0;
    std::_Get_pointer_type< Probationer<int(*) (int, int)> >::_Decltype::type j;
    j = g;
    std::_Get_pointer_type< Probationer2<int(*) (int, int)> >::type g2 = vb;
    std::_Get_pointer_type< Probationer2<int(*) (int, int)> >::_Decltype::type j2;
    j2 = g2;
    return 0;
}
что, если у класса _Ty есть type pointer, то именно он будет возвращён в
C++
1
typedef typename _Get_pointer_type<_Alloc>::type pointer;
, если же его нет, то будет возвращён type value_type.
Если же type value_type отсутствует, то у вас просто не скомпилируется код независимо от наличия type pointer.

Как это работает.
Внутри класса создается два шаблона функции _Fn без тела. Затем decltype пытается вычислить тип возвращаемого значения. Если у типа есть type pointer, то 0 как int является приоритетным выбором, среди перегруженных шаблонов. Если же данного типа нет, то 0 преобразуется к структуре _Wrap_int
C++
1
2
3
4
5
6
struct _Wrap_int
    {   // wraps int so that int argument is favored over _Wrap_int
    _Wrap_int(int)
        {   // do nothing
        }
    };
Мы видим, что у этой структуры как раз есть конструктор от int
И будет использован второй вариант шаблона _Fn

C++
1
2
3
4
5
template<class _Ty>
    struct _Identity
    {   // map _Ty to type unchanged, without operator()
    typedef _Ty type;
    };
Здесь все просто type просто вернет _Ty
Следовательно эта строчка
C++
1
typedef typename _Decltype::type type;
вернет то, что внутри _Identity, а из первого или второго, уже будет завесить от того есть ли type pointer или нет его.
Аналогично будут работать все остальные шаблоны обращающиеся к данному макросу.
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
29.10.2015, 07:52
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Чем _Get_pointer_type отличается от обычного получения типа указателя (C++):

Чем отличается Visual C++ от Borland C++? - C++
мужики у меня тут вопрос я конечно полный нуб еще:eek: а чем отличается Visual C++: от Borland C++ ? вроде ето один и тотже язык...

Передача типа указателя на функцию - C++
Всем привет. Недавно в теме начинающих возник вопрос, а можно ли передать тип (указатель на функцию) без использования typedef: ...

Чем _tmain отличается от обычного main ? - C++ Builder
Когда в RAD создаешь консольное приложение то изначально оно создается с функцией _tmain. Так чем собственно _tmain отличается от обычного...

Преобразование типа указателя на С++ Builder XE - C++ Builder
Всем здравствуйте, помогите пожалуйста со следующей проблемой! Установил С++Builder XE и загрузил в него полностью рабочий проект со...

Создание класса в RAD Studio, чем отличается от VC++? - C++ Builder
Пробовал реализовать класс в билдере точнее RadStudio, что я должен учитывать, при объявлении класса (вообще при создании класса,...

Long. Чем <long "тип"> отличается от простого типа - Visual C++
Long. Чем &lt;long &quot;тип&quot;&gt; отличается от простого типа Чем?

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
hoggy
Нарушитель
6566 / 2747 / 474
Регистрация: 15.11.2014
Сообщений: 6,096
Завершенные тесты: 1
30.10.2015, 23:35 #2
Цитата Сообщение от Archi0 Посмотреть сообщение
Возникает вопрос, а чем этот код отличается от обычного получения типа указателя.
эта техника называется SFINAE,
(в честь особенности шаблонов, которая так и называется SFINAE)
"сфинья" в простонародье.

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

например, можно узнать:
доступен ли в классе некоторый тайпдеф.
или есть ли у класса некоторая функция-член,
или данные-члены.

является ли класс наследником другого класса,
и тп.

тут все понятно.

но вот что вы подразумеваете под "обычном получении типа указателя"
уже не совсем понятно.

поэтому, не очевидно, что именно вы пытаетесь понять.
0
Archi0
28 / 14 / 4
Регистрация: 18.07.2013
Сообщений: 169
31.10.2015, 02:39  [ТС] #3
Вот это я имел ввиду под обычным
C++
1
2
3
4
5
6
template <class _Ty>
class Get_pointer
{
public:
    typedef _Ty* pointer;
};
А что я пытался понять, так это то к чему такие сложности нужны были в реализации
C++
1
typedef typename _Get_pointer_type<_Alloc>::type pointer
0
hoggy
Нарушитель
6566 / 2747 / 474
Регистрация: 15.11.2014
Сообщений: 6,096
Завершенные тесты: 1
31.10.2015, 17:52 #4
Цитата Сообщение от Archi0 Посмотреть сообщение
А что я пытался понять, так это то к чему такие сложности нужны были в реализации
typedef typename _Get_pointer_type<_Alloc>::type pointer
очевидно жеж, что _Get_pointer_type<_Alloc> рассчитана на то,
что бы обслуживать различные реализации возможных _Alloc

при этом таймпдеф pointer приоритетнее.
0
Archi0
28 / 14 / 4
Регистрация: 18.07.2013
Сообщений: 169
01.11.2015, 03:49  [ТС] #5
Очевидно, если знаешь как писать Alloc, только в книгах обычно рассказывается про стандартные контейнеры и алгоритмы с ними, а про Alloc ни слова, кроме того, что есть такой параметр. Вот и пришлось лезть в код и смотреть для чего это.

Вот попробовал реализовать линейную модель памяти

Кликните здесь для просмотра всего текста

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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#include "stdafx.h"
#include <vector>
#include <iostream>
#include <vector>
#include <stack>
#include <deque>
 
struct Probationer
{
    int x;
    int y;
    Probationer(int one, int two)
    {
        x = one;
        y = two;
    }
};
 
class LinearMemoryManager
{
    //_CRT_PACKING
private:
    void* buffer;
    void* current;
    size_t size;
    
public:
    
    template<class _Ty>
    struct _Allocator_base
    {   // base class for generic allocators
        typedef _Ty value_type;
    };
 
    LinearMemoryManager(size_t sizeBuff)
    {
        buffer = 0;
        buffer = new char[sizeBuff];
        if (buffer != 0) { size = sizeBuff; current = buffer; }
        else { size = 0; current = 0; }
    }
 
    ~LinearMemoryManager()
    {
        delete[] buffer;
    }
 
    ptrdiff_t Usage()
    {
        return (char*)current - (char*)buffer;
    }
 
    template<class _Ty> class LinearAlloc : public _Allocator_base < _Ty >
    {
    public:
        typedef LinearAlloc<_Ty> other;
        typedef _Allocator_base<_Ty> _Mybase;
        typedef typename _Mybase::value_type value_type;
        typedef value_type *pointer;
        typedef const value_type *const_pointer;
        typedef void *void_pointer;
        typedef const void *const_void_pointer;
        typedef value_type& reference;
        typedef const value_type& const_reference;
        typedef size_t size_type;
        typedef ptrdiff_t difference_type;
 
        LinearMemoryManager& lmm = RetCurrentMemoryManager();
        LinearAlloc() _THROW0()
        {   // construct default allocator (do nothing)
        }
 
        LinearAlloc<_Ty> select_on_container_copy_construction() const
        {   // return this allocator
            return (*this);
        }
 
        template<class _Other>
        struct rebind
        {   // convert this type to allocator<_Other>
            typedef LinearAlloc<_Other> other;
        };
 
        pointer address(reference _Val) const _NOEXCEPT
        {   // return address of mutable _Val
            return (_STD addressof(_Val));
        }
 
            const_pointer address(const_reference _Val) const _NOEXCEPT
        {   // return address of nonmutable _Val
            return (_STD addressof(_Val));
        }
 
            template<class _Other>
        LinearAlloc(const LinearAlloc<_Other>&) _THROW0()
        {   // construct from a related allocator (do nothing)
        }
 
        template<class _Other>
        LinearAlloc<_Ty>& operator=(const LinearAlloc<_Other>&)
        {   // assign from a related allocator (do nothing)
            return (*this);
        }
 
        void deallocate(pointer _Ptr, size_type)
        {   // deallocate object at _Ptr, ignore size
            if ( ((char*)lmm.current) - ((char*)_Ptr) - sizeof(_Ptr) < _CRT_PACKING) lmm.current = (void*)_Ptr;
            destroy(_Ptr);
        }
 
        pointer allocate(size_type _Count)
        {   // allocate array of _Count elements
            void *_Ptr = 0;
                if (_Count == 0);
                else if ((lmm.size - ((char*)lmm.current - (char*)lmm.buffer)) / sizeof(value_type) >= _Count)
                {
                    _Ptr = lmm.current;
                    if ((sizeof(value_type)*_Count) % _CRT_PACKING == 0) lmm.current = (void*)((pointer)lmm.current + _Count);
                    else { lmm.current = (void*)((pointer)lmm.current + _Count); lmm.current = (char*)lmm.current + _CRT_PACKING - (sizeof(value_type)*_Count) % _CRT_PACKING; }
                }
            return ((_Ty *)_Ptr);
        }
 
        pointer allocate(size_type _Count, const void *)
        {   // allocate array of _Count elements, ignore hint
            return (allocate(_Count));
        }
        void construct(_Ty *_Ptr)
        {   // default construct object at _Ptr
            ::new ((void *)_Ptr) _Ty();
        }
 
        void construct(_Ty *_Ptr, const _Ty& _Val)
        {   // construct object at _Ptr with value _Val
            ::new ((void *)_Ptr) _Ty(_Val);
        }
 
        template<class _Objty,
        class... _Types>
            void construct(_Objty *_Ptr, _Types&&... _Args)
        {   // construct _Objty(_Types...) at _Ptr
            ::new ((void *)_Ptr) _Objty(_STD forward<_Types>(_Args)...);
        }
 
        template<class _Uty>
        void destroy(_Uty *_Ptr)
        {   // destroy object at _Ptr
            _Ptr->~_Uty();
        }
 
        size_t max_size() const _THROW0()
        {   // estimate maximum array size
            return (lmm.size / sizeof(value_type));
        }
    };
    template <class _Ty>
    _Ty* allocate(size_t _Count)
    {
        LinearAlloc<_Ty> Alloc0;
        return Alloc0.allocate(_Count);
    }
 
    template <class _Ty>
    void construct(_Ty *_Ptr, const _Ty& _Val)
    {   // construct object at _Ptr with value _Val
        ::new ((void *)_Ptr) _Ty(_Val);
    }
 
    template<class _Objty, class... _Types>
    void construct(_Objty *_Ptr, _Types&&... _Args)
    {   // construct _Objty(_Types...) at _Ptr
        ::new ((void *)_Ptr) _Objty(_STD forward<_Types>(_Args)...);
    }
 
};
 
LinearMemoryManager lmm = LinearMemoryManager(1000);
LinearMemoryManager& RetCurrentMemoryManager()
{
    return lmm;
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    int x;
    std::vector<int, LinearMemoryManager::LinearAlloc<int> > fg;
    fg.push_back(1);
    fg.push_back(2);
    fg.push_back(3);
    fg.push_back(4);
    std::cout << std::endl << lmm.Usage() << std::endl;
    std::stack<int, std::deque<int, LinearMemoryManager::LinearAlloc<int> > > fg2;
    int j = 100;
    while (j > 0)   { fg2.push(1); j--; }
    Probationer *pptr = lmm.allocate<Probationer>(1);
    lmm.construct(pptr, Probationer(1, 2));
    lmm.construct(pptr, 1, 2);
    std::cout << pptr->x << " " << pptr->y;
    std::cout << std::endl << lmm.Usage() << std::endl;
    std::cout << lmm.Usage() << std::endl;
    std::cin >> x;
    return 0;
}


Пока костыль поставил в виде глобальной переменной вот думаю, что можно сделать для того, чтобы можно было несколько буферов создавать.
0
hoggy
Нарушитель
6566 / 2747 / 474
Регистрация: 15.11.2014
Сообщений: 6,096
Завершенные тесты: 1
01.11.2015, 10:27 #6
Цитата Сообщение от Archi0 Посмотреть сообщение
Очевидно, если знаешь как писать Alloc, только в книгах обычно рассказывается про стандартные контейнеры и алгоритмы с ними, а про Alloc ни слова
http://www.cplusplus.com/reference/memory/allocator/

Цитата Сообщение от Archi0 Посмотреть сообщение
template<class _Ty> class LinearAlloc : public _Allocator_base < _Ty >
очень плохая идея.

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


если интересно, то попозже
(предположительно в понедельник вечером)
я смогу выложить готовый пример-иллюстрацию кастомного stl-compatible аллокатора
1
Archi0
28 / 14 / 4
Регистрация: 18.07.2013
Сообщений: 169
01.11.2015, 10:41  [ТС] #7
Да будет полезно.
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.11.2015, 10:41
Привет! Вот еще темы с ответами:

Чем отличается указатель на массив от обычного указателя? - C (СИ)
Чем отличается указатель на массив от обычного указателя?

Чем отличается MVC от обычного проекта? - C# MVC
чем отличается MVC от обычного проекта на asp.net ?

Чем отличается сварочный трансформатор от обычного? - Электричество и магнетизм
Чем отличается сварочный трансформатор от обычного?

Чем отличается ActivePython от обычного python? - Python
Здравствуйте! Нашёл сайт ActiveState Python. Чем он отличается от обычного питона? Я так понял, что это какая то расширенная...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
01.11.2015, 10:41
Ответ Создать тему
Опции темы

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