質問編集履歴
4
補足
title
CHANGED
File without changes
|
body
CHANGED
@@ -308,4 +308,9 @@
|
|
308
308
|
|
309
309
|
return 0;
|
310
310
|
}
|
311
|
-
```
|
311
|
+
```
|
312
|
+
|
313
|
+
【補足】
|
314
|
+
`gContainerList`への値設定時、初期化リストを使おうとしたのでずか、ContainerHolderのコピー・コンストラクタが呼び出され、unique_ptrを使っているので暗黙的にdeleteされており、コンパイル・エラーでした。
|
315
|
+
push_backやemplace_backではムーブだけでよいので、原因はよく分かりませんでした。
|
316
|
+
もし、分かる方がいらっしゃいましたら、何故初期化リストではコピー・コンストラクタが必要になるのかご教授頂けると幸いです。
|
3
自作
title
CHANGED
File without changes
|
body
CHANGED
@@ -52,4 +52,260 @@
|
|
52
52
|
たぶん、イテレータにboost:anyテクニックを応用すれば可能と思いますが、コピー時にnewすることになります。イテレータはコピー負荷が軽いことが前提な型っぽい(I/Fの多くが参照渡しではなく値渡し)ので、これは避けたいです。
|
53
53
|
|
54
54
|
以前、[こちらで質問](https://teratail.com/questions/28543)し、その過程で思いついたものの改造版を[Qiitaへ投稿](http://qiita.com/Chironian/items/19575744d4e5ea53c648)しました。
|
55
|
-
そのRangeクラス内にboost::anyテクニックを使って、異なるコンテナ用イテレータを保持することで対応できそうな気がしているのですが、その前に何か良いアイデアがあればと思い、質問させて頂いています。
|
55
|
+
そのRangeクラス内にboost::anyテクニックを使って、異なるコンテナ用イテレータを保持することで対応できそうな気がしているのですが、その前に何か良いアイデアがあればと思い、質問させて頂いています。
|
56
|
+
|
57
|
+
###自作してみました
|
58
|
+
yohhoyさんに教えていただいたboostの実装を参考にしつつ、自作してみました。
|
59
|
+
イテレータではなく範囲ベースfor専用のレンジをboost:any的に保持してます。
|
60
|
+
範囲ベースfor専用のレンジはQiitaへ投稿した[range-based forをより使いやすくする](http://qiita.com/Chironian/items/19575744d4e5ea53c648)を改造しました。
|
61
|
+
|
62
|
+
後、下記ソースではContainerHolderもboost::anyのようにしてますが、こちらは勿体無い気がしてます。コンテナへの参照をunique_ptr<>で保持してます。わざわざヒープ領域に「参照変数領域」を確保していることになるので、なんか違う気がするのですが、良い方法を思いつきませんでした。
|
63
|
+
|
64
|
+
poly_range.h
|
65
|
+
```C++
|
66
|
+
#ifndef POLY_RANGE_H
|
67
|
+
#define POLY_RANGE_H
|
68
|
+
|
69
|
+
#include <memory>
|
70
|
+
|
71
|
+
//----------------------------------------------------------------------------
|
72
|
+
// 範囲ベースforへ渡すリファレンサー(RBForReferencerの特化)
|
73
|
+
//----------------------------------------------------------------------------
|
74
|
+
|
75
|
+
template<class tPolyRangeBase, class tElementBase>
|
76
|
+
class PolyReferencer
|
77
|
+
{
|
78
|
+
tPolyRangeBase& mPolyRange;
|
79
|
+
public:
|
80
|
+
PolyReferencer(tPolyRangeBase& iPolyRange) : mPolyRange(iPolyRange)
|
81
|
+
{ }
|
82
|
+
|
83
|
+
tElementBase& operator*()
|
84
|
+
{
|
85
|
+
return mPolyRange.mHolder->front();
|
86
|
+
}
|
87
|
+
tElementBase const& operator*() const
|
88
|
+
{
|
89
|
+
return mPolyRange.mHolder->front();
|
90
|
+
}
|
91
|
+
void operator++()
|
92
|
+
{
|
93
|
+
mPolyRange.mHolder->drop_front();
|
94
|
+
}
|
95
|
+
bool operator!=(PolyReferencer const& iRhs) const
|
96
|
+
{
|
97
|
+
if (!mPolyRange.mHolder.get())
|
98
|
+
return false;
|
99
|
+
return !mPolyRange.mHolder->empty();
|
100
|
+
}
|
101
|
+
};
|
102
|
+
|
103
|
+
//----------------------------------------------------------------------------
|
104
|
+
// 枚挙用Range
|
105
|
+
//----------------------------------------------------------------------------
|
106
|
+
|
107
|
+
template<class tElementBase>
|
108
|
+
class PolyRange
|
109
|
+
{
|
110
|
+
|
111
|
+
// ---<<< 基底クラス >>>---
|
112
|
+
|
113
|
+
struct HolderBase
|
114
|
+
{
|
115
|
+
virtual tElementBase & front() = 0;
|
116
|
+
virtual tElementBase const& front() const = 0;
|
117
|
+
virtual void drop_front() = 0;
|
118
|
+
virtual bool empty() const = 0;
|
119
|
+
|
120
|
+
// これがないとmsvc 2015の「反復子のデバッグのサポート」用の
|
121
|
+
// イテレータのデストラクタが呼ばれないため、異常動作する。
|
122
|
+
virtual ~HolderBase() { }
|
123
|
+
};
|
124
|
+
|
125
|
+
// ---<<< 実クラス >>>---
|
126
|
+
|
127
|
+
template<typename tIterator>
|
128
|
+
struct Holder : public HolderBase
|
129
|
+
{
|
130
|
+
tIterator mBegin;
|
131
|
+
tIterator mEnd;
|
132
|
+
|
133
|
+
Holder(tIterator&& iBegin, tIterator&& iEnd) :
|
134
|
+
mBegin(std::forward<tIterator>(iBegin)),
|
135
|
+
mEnd (std::forward<tIterator>(iEnd))
|
136
|
+
{ }
|
137
|
+
~Holder() = default;
|
138
|
+
|
139
|
+
tElementBase& front()
|
140
|
+
{
|
141
|
+
return *mBegin;
|
142
|
+
}
|
143
|
+
tElementBase const& front() const
|
144
|
+
{
|
145
|
+
return *mBegin;
|
146
|
+
}
|
147
|
+
void drop_front()
|
148
|
+
{
|
149
|
+
++mBegin;
|
150
|
+
}
|
151
|
+
bool empty() const
|
152
|
+
{
|
153
|
+
return mBegin == mEnd;
|
154
|
+
}
|
155
|
+
};
|
156
|
+
|
157
|
+
// ---<<< 各種設定 >>>---
|
158
|
+
|
159
|
+
template<class, class> friend class PolyReferencer;
|
160
|
+
typedef PolyReferencer<PolyRange, tElementBase> PolyReferencer;
|
161
|
+
|
162
|
+
// ---<<< 記録領域 >>>---
|
163
|
+
|
164
|
+
std::unique_ptr<HolderBase> mHolder;
|
165
|
+
|
166
|
+
// ---<<< コンストラクタ >>>---
|
167
|
+
|
168
|
+
public:
|
169
|
+
PolyRange() { }
|
170
|
+
|
171
|
+
template<typename tIterator>
|
172
|
+
PolyRange(tIterator&& iBegin, tIterator&& iEnd) :
|
173
|
+
mHolder
|
174
|
+
(
|
175
|
+
new Holder<tIterator>
|
176
|
+
(
|
177
|
+
std::forward<tIterator>(iBegin),
|
178
|
+
std::forward<tIterator>(iEnd)
|
179
|
+
)
|
180
|
+
)
|
181
|
+
{ }
|
182
|
+
|
183
|
+
PolyReferencer begin() {return PolyReferencer(*this);}
|
184
|
+
PolyReferencer end() {return PolyReferencer(*this);}
|
185
|
+
};
|
186
|
+
|
187
|
+
//----------------------------------------------------------------------------
|
188
|
+
// コンテナのホルダ
|
189
|
+
// 保持しているコンテナの範囲ベースfor専用Rangeを獲得する機能を持つ
|
190
|
+
//----------------------------------------------------------------------------
|
191
|
+
|
192
|
+
template<class tElementBase>
|
193
|
+
class ContainerHolder
|
194
|
+
{
|
195
|
+
|
196
|
+
// ---<<< 基底クラス >>>---
|
197
|
+
|
198
|
+
struct HolderBase
|
199
|
+
{
|
200
|
+
virtual ~HolderBase() { }
|
201
|
+
virtual PolyRange<tElementBase> getRange() = 0;
|
202
|
+
};
|
203
|
+
|
204
|
+
// ---<<< 実クラス >>>---
|
205
|
+
|
206
|
+
template<class tContainer>
|
207
|
+
struct Holder : public HolderBase
|
208
|
+
{
|
209
|
+
tContainer& mContainer;
|
210
|
+
|
211
|
+
Holder(tContainer& iContainer) : mContainer(iContainer)
|
212
|
+
{ }
|
213
|
+
~Holder() = default;
|
214
|
+
|
215
|
+
PolyRange<tElementBase> getRange()
|
216
|
+
{
|
217
|
+
return PolyRange<tElementBase>(std::begin(mContainer), std::end(mContainer));
|
218
|
+
}
|
219
|
+
};
|
220
|
+
|
221
|
+
// ---<<< 記録領域 >>>---
|
222
|
+
|
223
|
+
std::unique_ptr<HolderBase> mHolder;
|
224
|
+
|
225
|
+
// ---<<< コンストラクタ >>>---
|
226
|
+
|
227
|
+
public:
|
228
|
+
template<typename tContainer>
|
229
|
+
ContainerHolder(tContainer& iContainer) :
|
230
|
+
mHolder(new Holder<tContainer>(iContainer))
|
231
|
+
{ }
|
232
|
+
|
233
|
+
PolyRange<tElementBase> getRange()
|
234
|
+
{
|
235
|
+
return mHolder->getRange();
|
236
|
+
}
|
237
|
+
};
|
238
|
+
|
239
|
+
#endif // POLY_RANGE_H
|
240
|
+
```
|
241
|
+
|
242
|
+
以下、サンプル・ソースです。
|
243
|
+
main.cpp
|
244
|
+
```C++
|
245
|
+
#include <iostream>
|
246
|
+
#include <vector>
|
247
|
+
#include <string>
|
248
|
+
#include "poly_range.h"
|
249
|
+
|
250
|
+
// 要素の型
|
251
|
+
struct ElementBase
|
252
|
+
{
|
253
|
+
virtual ~ElementBase() { }
|
254
|
+
virtual char const* getName() = 0;
|
255
|
+
};
|
256
|
+
|
257
|
+
struct Foo : public ElementBase
|
258
|
+
{
|
259
|
+
std::string const mName;
|
260
|
+
char const* getName()
|
261
|
+
{
|
262
|
+
return mName.c_str();
|
263
|
+
}
|
264
|
+
|
265
|
+
Foo(std::string const& iName) : mName(iName) { }
|
266
|
+
};
|
267
|
+
|
268
|
+
struct Bar : public ElementBase
|
269
|
+
{
|
270
|
+
char const* mName;
|
271
|
+
char const* getName()
|
272
|
+
{
|
273
|
+
return mName;
|
274
|
+
}
|
275
|
+
|
276
|
+
Bar(char const* iName) : mName(iName) { }
|
277
|
+
};
|
278
|
+
|
279
|
+
// コンテナ
|
280
|
+
Foo gFooArray[]={ {"Foo0"}, {"Foo1"}, {"Foo2"} };
|
281
|
+
std::vector<Bar> gBarVector={ "Bar0", "Bar1", "Bar2" };
|
282
|
+
|
283
|
+
// コンテナのリスト
|
284
|
+
typedef ContainerHolder<ElementBase> Container;
|
285
|
+
std::vector<Container> gContainerList;
|
286
|
+
|
287
|
+
int main()
|
288
|
+
{
|
289
|
+
std::size_t aFooArrayIndex=gContainerList.size();
|
290
|
+
gContainerList.emplace_back(Container(gFooArray));
|
291
|
+
|
292
|
+
std::size_t aBarVectorIndex=gContainerList.size();
|
293
|
+
gContainerList.emplace_back(Container(gBarVector));
|
294
|
+
|
295
|
+
std::cout << "--- FooArray ---\n";
|
296
|
+
for (auto&& element : gContainerList[aFooArrayIndex].getRange())
|
297
|
+
{
|
298
|
+
std::cout << element.getName() << "\n";
|
299
|
+
}
|
300
|
+
std::cout << "\n";
|
301
|
+
|
302
|
+
std::cout << "--- BarVector ---\n";
|
303
|
+
for (auto&& element : gContainerList[aBarVectorIndex].getRange())
|
304
|
+
{
|
305
|
+
std::cout << element.getName() << "\n";
|
306
|
+
}
|
307
|
+
std::cout << "\n";
|
308
|
+
|
309
|
+
return 0;
|
310
|
+
}
|
311
|
+
```
|
2
不足追加
title
CHANGED
File without changes
|
body
CHANGED
@@ -5,16 +5,32 @@
|
|
5
5
|
そのようなクラスをご存知の方、もしくは、簡単な方法をご存知の方がいましたら、是非、ご教授頂けないでしょうか?
|
6
6
|
|
7
7
|
#####詳細
|
8
|
-
例えば、下記のようなコンテナが
|
8
|
+
例えば、下記のようなコンテナaFooArray[]とstd::vector<Bar>があるとします。
|
9
9
|
```C++
|
10
|
-
|
10
|
+
struct ElementBase
|
11
11
|
{
|
12
|
+
virutal ~ElementBase() { }
|
13
|
+
virtual char const* getName() = 0;
|
14
|
+
};
|
15
|
+
|
16
|
+
struct Foo : public ElementBase
|
17
|
+
{
|
18
|
+
std::string const mName;
|
19
|
+
char const* getName()
|
20
|
+
{
|
21
|
+
return mName.c_str();
|
22
|
+
}
|
12
23
|
:
|
13
24
|
};
|
14
25
|
Foo aFooArray[]={ ... };
|
15
26
|
|
16
|
-
|
27
|
+
struct Bar : public ElementBase
|
17
28
|
{
|
29
|
+
char const* mName;
|
30
|
+
char const* getName()
|
31
|
+
{
|
32
|
+
return mName;
|
33
|
+
}
|
18
34
|
:
|
19
35
|
};
|
20
36
|
std::vector<Bar> aBarVector={ ... };
|
@@ -29,6 +45,7 @@
|
|
29
45
|
```C++
|
30
46
|
for (auto&& element : aContainerList[index].getRange())
|
31
47
|
{
|
48
|
+
std::cout << element.getName() << "\n";
|
32
49
|
}
|
33
50
|
```
|
34
51
|
|
1
表現修正とミス修正
title
CHANGED
File without changes
|
body
CHANGED
@@ -1,20 +1,25 @@
|
|
1
|
-
生配列やvector等の要素を枚挙することは
|
1
|
+
生配列やvector等の要素を枚挙することは多いと思います。
|
2
|
-
そ
|
2
|
+
その延長線上で、異なる型のコンテナの要素をポリモーフィズム的に枚挙したいのですが、最近のC++なら簡単と思っていたら、意外に難しいです。
|
3
|
-
|
3
|
+
|
4
4
|
しかし、実は私がまだ把握できていない標準ライブラリやboost等にそのような機能をサポートしたクラスがありそうな気もしています。
|
5
|
-
|
6
5
|
そのようなクラスをご存知の方、もしくは、簡単な方法をご存知の方がいましたら、是非、ご教授頂けないでしょうか?
|
7
6
|
|
8
7
|
#####詳細
|
9
8
|
例えば、下記のようなコンテナが2つあるとします。
|
10
9
|
```C++
|
11
|
-
class Foo
|
10
|
+
class Foo
|
11
|
+
{
|
12
|
+
:
|
13
|
+
};
|
12
14
|
Foo aFooArray[]={ ... };
|
13
15
|
|
14
|
-
class Bar
|
16
|
+
class Bar
|
17
|
+
{
|
18
|
+
:
|
19
|
+
};
|
15
20
|
std::vector<Bar> aBarVector={ ... };
|
16
21
|
```
|
17
|
-
[boost:
|
22
|
+
[boost:any](http://cpplover.blogspot.jp/2007/02/inside-boostany.html)的なテクニックでそれぞれへのポインタを管理用コンテナに入れてます。
|
18
23
|
イメージは下記です。(実際にビルドしてないので雰囲気だけ。)
|
19
24
|
```C++
|
20
25
|
std::vector<any> aContainerList={any(aFooArray), any(aBarVector)};
|
@@ -22,7 +27,7 @@
|
|
22
27
|
|
23
28
|
そして、下記のようなイメージで枚挙処理を行いたいのです。
|
24
29
|
```C++
|
25
|
-
for (auto&& : aContainerList[index].getRange())
|
30
|
+
for (auto&& element : aContainerList[index].getRange())
|
26
31
|
{
|
27
32
|
}
|
28
33
|
```
|