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

C++

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

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

29.10.2015, 07:52. Просмотров 326. Ответов 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 или нет его.
Аналогично будут работать все остальные шаблоны обращающиеся к данному макросу.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
29.10.2015, 07:52     Чем _Get_pointer_type отличается от обычного получения типа указателя
Посмотрите здесь:

Чем отличается fstream от ofstream? C++
C++ Чем отличается С++ от Visual С++?
Чем отличается vector<> от set<> а? C++
Чем отличается ln , lg, и log ? C++
C++ Builder Чем _tmain отличается от обычного main ?
Чем отличается оператор цикла C++
C++ Чем new отличается от malloc?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
hoggy
5989 / 2429 / 436
Регистрация: 15.11.2014
Сообщений: 5,381
Завершенные тесты: 1
30.10.2015, 23:35     Чем _Get_pointer_type отличается от обычного получения типа указателя #2
Цитата Сообщение от Archi0 Посмотреть сообщение
Возникает вопрос, а чем этот код отличается от обычного получения типа указателя.
эта техника называется SFINAE,
(в честь особенности шаблонов, которая так и называется SFINAE)
"сфинья" в простонародье.

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

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

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

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

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

поэтому, не очевидно, что именно вы пытаетесь понять.
Archi0
28 / 14 / 4
Регистрация: 18.07.2013
Сообщений: 166
31.10.2015, 02:39  [ТС]     Чем _Get_pointer_type отличается от обычного получения типа указателя #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
hoggy
5989 / 2429 / 436
Регистрация: 15.11.2014
Сообщений: 5,381
Завершенные тесты: 1
31.10.2015, 17:52     Чем _Get_pointer_type отличается от обычного получения типа указателя #4
Цитата Сообщение от Archi0 Посмотреть сообщение
А что я пытался понять, так это то к чему такие сложности нужны были в реализации
typedef typename _Get_pointer_type<_Alloc>::type pointer
очевидно жеж, что _Get_pointer_type<_Alloc> рассчитана на то,
что бы обслуживать различные реализации возможных _Alloc

при этом таймпдеф pointer приоритетнее.
Archi0
28 / 14 / 4
Регистрация: 18.07.2013
Сообщений: 166
01.11.2015, 03:49  [ТС]     Чем _Get_pointer_type отличается от обычного получения типа указателя #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;
}


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

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

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


если интересно, то попозже
(предположительно в понедельник вечером)
я смогу выложить готовый пример-иллюстрацию кастомного stl-compatible аллокатора
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.11.2015, 10:41     Чем _Get_pointer_type отличается от обычного получения типа указателя
Еще ссылки по теме:

C++ Чем ссылка отличается от указателя?
C++ Чем отличается Абстрагирование от Наследования?
Long. Чем <long "тип"> отличается от простого типа Visual C++
C++ Чем отличается istringstream от stringstream?
C++ Объяснить, что делает операция *& и чем она отличается от простого указателя?

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

Или воспользуйтесь поиском по форуму:
Archi0
28 / 14 / 4
Регистрация: 18.07.2013
Сообщений: 166
01.11.2015, 10:41  [ТС]     Чем _Get_pointer_type отличается от обычного получения типа указателя #7
Да будет полезно.
Yandex
Объявления
01.11.2015, 10:41     Чем _Get_pointer_type отличается от обычного получения типа указателя
Ответ Создать тему
Опции темы

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