質問編集履歴

4

補足

2016/05/14 05:15

投稿

Chironian
Chironian

スコア23272

test CHANGED
File without changes
test CHANGED
@@ -619,3 +619,13 @@
619
619
  }
620
620
 
621
621
  ```
622
+
623
+
624
+
625
+ 【補足】
626
+
627
+ `gContainerList`への値設定時、初期化リストを使おうとしたのでずか、ContainerHolderのコピー・コンストラクタが呼び出され、unique_ptrを使っているので暗黙的にdeleteされており、コンパイル・エラーでした。
628
+
629
+ push_backやemplace_backではムーブだけでよいので、原因はよく分かりませんでした。
630
+
631
+ もし、分かる方がいらっしゃいましたら、何故初期化リストではコピー・コンストラクタが必要になるのかご教授頂けると幸いです。

3

自作

2016/05/14 05:15

投稿

Chironian
Chironian

スコア23272

test CHANGED
File without changes
test CHANGED
@@ -107,3 +107,515 @@
107
107
  以前、[こちらで質問](https://teratail.com/questions/28543)し、その過程で思いついたものの改造版を[Qiitaへ投稿](http://qiita.com/Chironian/items/19575744d4e5ea53c648)しました。
108
108
 
109
109
  そのRangeクラス内にboost::anyテクニックを使って、異なるコンテナ用イテレータを保持することで対応できそうな気がしているのですが、その前に何か良いアイデアがあればと思い、質問させて頂いています。
110
+
111
+
112
+
113
+ ###自作してみました
114
+
115
+ yohhoyさんに教えていただいたboostの実装を参考にしつつ、自作してみました。
116
+
117
+ イテレータではなく範囲ベースfor専用のレンジをboost:any的に保持してます。
118
+
119
+ 範囲ベースfor専用のレンジはQiitaへ投稿した[range-based forをより使いやすくする](http://qiita.com/Chironian/items/19575744d4e5ea53c648)を改造しました。
120
+
121
+
122
+
123
+ 後、下記ソースではContainerHolderもboost::anyのようにしてますが、こちらは勿体無い気がしてます。コンテナへの参照をunique_ptr<>で保持してます。わざわざヒープ領域に「参照変数領域」を確保していることになるので、なんか違う気がするのですが、良い方法を思いつきませんでした。
124
+
125
+
126
+
127
+ poly_range.h
128
+
129
+ ```C++
130
+
131
+ #ifndef POLY_RANGE_H
132
+
133
+ #define POLY_RANGE_H
134
+
135
+
136
+
137
+ #include <memory>
138
+
139
+
140
+
141
+ //----------------------------------------------------------------------------
142
+
143
+ // 範囲ベースforへ渡すリファレンサー(RBForReferencerの特化)
144
+
145
+ //----------------------------------------------------------------------------
146
+
147
+
148
+
149
+ template<class tPolyRangeBase, class tElementBase>
150
+
151
+ class PolyReferencer
152
+
153
+ {
154
+
155
+ tPolyRangeBase& mPolyRange;
156
+
157
+ public:
158
+
159
+ PolyReferencer(tPolyRangeBase& iPolyRange) : mPolyRange(iPolyRange)
160
+
161
+ { }
162
+
163
+
164
+
165
+ tElementBase& operator*()
166
+
167
+ {
168
+
169
+ return mPolyRange.mHolder->front();
170
+
171
+ }
172
+
173
+ tElementBase const& operator*() const
174
+
175
+ {
176
+
177
+ return mPolyRange.mHolder->front();
178
+
179
+ }
180
+
181
+ void operator++()
182
+
183
+ {
184
+
185
+ mPolyRange.mHolder->drop_front();
186
+
187
+ }
188
+
189
+ bool operator!=(PolyReferencer const& iRhs) const
190
+
191
+ {
192
+
193
+ if (!mPolyRange.mHolder.get())
194
+
195
+ return false;
196
+
197
+ return !mPolyRange.mHolder->empty();
198
+
199
+ }
200
+
201
+ };
202
+
203
+
204
+
205
+ //----------------------------------------------------------------------------
206
+
207
+ // 枚挙用Range
208
+
209
+ //----------------------------------------------------------------------------
210
+
211
+
212
+
213
+ template<class tElementBase>
214
+
215
+ class PolyRange
216
+
217
+ {
218
+
219
+
220
+
221
+ // ---<<< 基底クラス >>>---
222
+
223
+
224
+
225
+ struct HolderBase
226
+
227
+ {
228
+
229
+ virtual tElementBase & front() = 0;
230
+
231
+ virtual tElementBase const& front() const = 0;
232
+
233
+ virtual void drop_front() = 0;
234
+
235
+ virtual bool empty() const = 0;
236
+
237
+
238
+
239
+ // これがないとmsvc 2015の「反復子のデバッグのサポート」用の
240
+
241
+ // イテレータのデストラクタが呼ばれないため、異常動作する。
242
+
243
+ virtual ~HolderBase() { }
244
+
245
+ };
246
+
247
+
248
+
249
+ // ---<<< 実クラス >>>---
250
+
251
+
252
+
253
+ template<typename tIterator>
254
+
255
+ struct Holder : public HolderBase
256
+
257
+ {
258
+
259
+ tIterator mBegin;
260
+
261
+ tIterator mEnd;
262
+
263
+
264
+
265
+ Holder(tIterator&& iBegin, tIterator&& iEnd) :
266
+
267
+ mBegin(std::forward<tIterator>(iBegin)),
268
+
269
+ mEnd (std::forward<tIterator>(iEnd))
270
+
271
+ { }
272
+
273
+ ~Holder() = default;
274
+
275
+
276
+
277
+ tElementBase& front()
278
+
279
+ {
280
+
281
+ return *mBegin;
282
+
283
+ }
284
+
285
+ tElementBase const& front() const
286
+
287
+ {
288
+
289
+ return *mBegin;
290
+
291
+ }
292
+
293
+ void drop_front()
294
+
295
+ {
296
+
297
+ ++mBegin;
298
+
299
+ }
300
+
301
+ bool empty() const
302
+
303
+ {
304
+
305
+ return mBegin == mEnd;
306
+
307
+ }
308
+
309
+ };
310
+
311
+
312
+
313
+ // ---<<< 各種設定 >>>---
314
+
315
+
316
+
317
+ template<class, class> friend class PolyReferencer;
318
+
319
+ typedef PolyReferencer<PolyRange, tElementBase> PolyReferencer;
320
+
321
+
322
+
323
+ // ---<<< 記録領域 >>>---
324
+
325
+
326
+
327
+ std::unique_ptr<HolderBase> mHolder;
328
+
329
+
330
+
331
+ // ---<<< コンストラクタ >>>---
332
+
333
+
334
+
335
+ public:
336
+
337
+ PolyRange() { }
338
+
339
+
340
+
341
+ template<typename tIterator>
342
+
343
+ PolyRange(tIterator&& iBegin, tIterator&& iEnd) :
344
+
345
+ mHolder
346
+
347
+ (
348
+
349
+ new Holder<tIterator>
350
+
351
+ (
352
+
353
+ std::forward<tIterator>(iBegin),
354
+
355
+ std::forward<tIterator>(iEnd)
356
+
357
+ )
358
+
359
+ )
360
+
361
+ { }
362
+
363
+
364
+
365
+ PolyReferencer begin() {return PolyReferencer(*this);}
366
+
367
+ PolyReferencer end() {return PolyReferencer(*this);}
368
+
369
+ };
370
+
371
+
372
+
373
+ //----------------------------------------------------------------------------
374
+
375
+ // コンテナのホルダ
376
+
377
+ // 保持しているコンテナの範囲ベースfor専用Rangeを獲得する機能を持つ
378
+
379
+ //----------------------------------------------------------------------------
380
+
381
+
382
+
383
+ template<class tElementBase>
384
+
385
+ class ContainerHolder
386
+
387
+ {
388
+
389
+
390
+
391
+ // ---<<< 基底クラス >>>---
392
+
393
+
394
+
395
+ struct HolderBase
396
+
397
+ {
398
+
399
+ virtual ~HolderBase() { }
400
+
401
+ virtual PolyRange<tElementBase> getRange() = 0;
402
+
403
+ };
404
+
405
+
406
+
407
+ // ---<<< 実クラス >>>---
408
+
409
+
410
+
411
+ template<class tContainer>
412
+
413
+ struct Holder : public HolderBase
414
+
415
+ {
416
+
417
+ tContainer& mContainer;
418
+
419
+
420
+
421
+ Holder(tContainer& iContainer) : mContainer(iContainer)
422
+
423
+ { }
424
+
425
+ ~Holder() = default;
426
+
427
+
428
+
429
+ PolyRange<tElementBase> getRange()
430
+
431
+ {
432
+
433
+ return PolyRange<tElementBase>(std::begin(mContainer), std::end(mContainer));
434
+
435
+ }
436
+
437
+ };
438
+
439
+
440
+
441
+ // ---<<< 記録領域 >>>---
442
+
443
+
444
+
445
+ std::unique_ptr<HolderBase> mHolder;
446
+
447
+
448
+
449
+ // ---<<< コンストラクタ >>>---
450
+
451
+
452
+
453
+ public:
454
+
455
+ template<typename tContainer>
456
+
457
+ ContainerHolder(tContainer& iContainer) :
458
+
459
+ mHolder(new Holder<tContainer>(iContainer))
460
+
461
+ { }
462
+
463
+
464
+
465
+ PolyRange<tElementBase> getRange()
466
+
467
+ {
468
+
469
+ return mHolder->getRange();
470
+
471
+ }
472
+
473
+ };
474
+
475
+
476
+
477
+ #endif // POLY_RANGE_H
478
+
479
+ ```
480
+
481
+
482
+
483
+ 以下、サンプル・ソースです。
484
+
485
+ main.cpp
486
+
487
+ ```C++
488
+
489
+ #include <iostream>
490
+
491
+ #include <vector>
492
+
493
+ #include <string>
494
+
495
+ #include "poly_range.h"
496
+
497
+
498
+
499
+ // 要素の型
500
+
501
+ struct ElementBase
502
+
503
+ {
504
+
505
+ virtual ~ElementBase() { }
506
+
507
+ virtual char const* getName() = 0;
508
+
509
+ };
510
+
511
+
512
+
513
+ struct Foo : public ElementBase
514
+
515
+ {
516
+
517
+ std::string const mName;
518
+
519
+ char const* getName()
520
+
521
+ {
522
+
523
+ return mName.c_str();
524
+
525
+ }
526
+
527
+
528
+
529
+ Foo(std::string const& iName) : mName(iName) { }
530
+
531
+ };
532
+
533
+
534
+
535
+ struct Bar : public ElementBase
536
+
537
+ {
538
+
539
+ char const* mName;
540
+
541
+ char const* getName()
542
+
543
+ {
544
+
545
+ return mName;
546
+
547
+ }
548
+
549
+
550
+
551
+ Bar(char const* iName) : mName(iName) { }
552
+
553
+ };
554
+
555
+
556
+
557
+ // コンテナ
558
+
559
+ Foo gFooArray[]={ {"Foo0"}, {"Foo1"}, {"Foo2"} };
560
+
561
+ std::vector<Bar> gBarVector={ "Bar0", "Bar1", "Bar2" };
562
+
563
+
564
+
565
+ // コンテナのリスト
566
+
567
+ typedef ContainerHolder<ElementBase> Container;
568
+
569
+ std::vector<Container> gContainerList;
570
+
571
+
572
+
573
+ int main()
574
+
575
+ {
576
+
577
+ std::size_t aFooArrayIndex=gContainerList.size();
578
+
579
+ gContainerList.emplace_back(Container(gFooArray));
580
+
581
+
582
+
583
+ std::size_t aBarVectorIndex=gContainerList.size();
584
+
585
+ gContainerList.emplace_back(Container(gBarVector));
586
+
587
+
588
+
589
+ std::cout << "--- FooArray ---\n";
590
+
591
+ for (auto&& element : gContainerList[aFooArrayIndex].getRange())
592
+
593
+ {
594
+
595
+ std::cout << element.getName() << "\n";
596
+
597
+ }
598
+
599
+ std::cout << "\n";
600
+
601
+
602
+
603
+ std::cout << "--- BarVector ---\n";
604
+
605
+ for (auto&& element : gContainerList[aBarVectorIndex].getRange())
606
+
607
+ {
608
+
609
+ std::cout << element.getName() << "\n";
610
+
611
+ }
612
+
613
+ std::cout << "\n";
614
+
615
+
616
+
617
+ return 0;
618
+
619
+ }
620
+
621
+ ```

2

不足追加

2016/05/14 05:00

投稿

Chironian
Chironian

スコア23272

test CHANGED
File without changes
test CHANGED
@@ -12,13 +12,35 @@
12
12
 
13
13
  #####詳細
14
14
 
15
- 例えば、下記のようなコンテナが2つあるとします。
15
+ 例えば、下記のようなコンテナaFooArray[]とstd::vector<Bar>があるとします。
16
16
 
17
17
  ```C++
18
18
 
19
- class Foo
19
+ struct ElementBase
20
20
 
21
21
  {
22
+
23
+ virutal ~ElementBase() { }
24
+
25
+ virtual char const* getName() = 0;
26
+
27
+ };
28
+
29
+
30
+
31
+ struct Foo : public ElementBase
32
+
33
+ {
34
+
35
+ std::string const mName;
36
+
37
+ char const* getName()
38
+
39
+ {
40
+
41
+ return mName.c_str();
42
+
43
+ }
22
44
 
23
45
  :
24
46
 
@@ -28,9 +50,19 @@
28
50
 
29
51
 
30
52
 
31
- class Bar
53
+ struct Bar : public ElementBase
32
54
 
33
55
  {
56
+
57
+ char const* mName;
58
+
59
+ char const* getName()
60
+
61
+ {
62
+
63
+ return mName;
64
+
65
+ }
34
66
 
35
67
  :
36
68
 
@@ -60,6 +92,8 @@
60
92
 
61
93
  {
62
94
 
95
+ std::cout << element.getName() << "\n";
96
+
63
97
  }
64
98
 
65
99
  ```

1

表現修正とミス修正

2016/05/08 08:43

投稿

Chironian
Chironian

スコア23272

test CHANGED
File without changes
test CHANGED
@@ -1,12 +1,10 @@
1
- 生配列やvector等の要素を枚挙することは非常に多いと思います。
1
+ 生配列やvector等の要素を枚挙することは多いと思います。
2
2
 
3
- して、異なる型のコンテナの要素をポリモーフィズム的に枚挙したいのです。
3
+ の延長線上で、異なる型のコンテナの要素をポリモーフィズム的に枚挙したいのですが、最近のC++なら簡単と思っていたら、意外に難しいです
4
4
 
5
- 最近のC++なら簡単かと思っていたら、意外に難しいです。
5
+
6
6
 
7
7
  しかし、実は私がまだ把握できていない標準ライブラリやboost等にそのような機能をサポートしたクラスがありそうな気もしています。
8
-
9
-
10
8
 
11
9
  そのようなクラスをご存知の方、もしくは、簡単な方法をご存知の方がいましたら、是非、ご教授頂けないでしょうか?
12
10
 
@@ -18,19 +16,31 @@
18
16
 
19
17
  ```C++
20
18
 
21
- class Foo;
19
+ class Foo
20
+
21
+ {
22
+
23
+ :
24
+
25
+ };
22
26
 
23
27
  Foo aFooArray[]={ ... };
24
28
 
25
29
 
26
30
 
27
- class Bar;
31
+ class Bar
32
+
33
+ {
34
+
35
+ :
36
+
37
+ };
28
38
 
29
39
  std::vector<Bar> aBarVector={ ... };
30
40
 
31
41
  ```
32
42
 
33
- [boost:Any](http://cpplover.blogspot.jp/2007/02/inside-boostany.html)的なテクニックでそれぞれへのポインタを管理用コンテナに入れてます。
43
+ [boost:any](http://cpplover.blogspot.jp/2007/02/inside-boostany.html)的なテクニックでそれぞれへのポインタを管理用コンテナに入れてます。
34
44
 
35
45
  イメージは下記です。(実際にビルドしてないので雰囲気だけ。)
36
46
 
@@ -46,7 +56,7 @@
46
56
 
47
57
  ```C++
48
58
 
49
- for (auto&& : aContainerList[index].getRange())
59
+ for (auto&& element : aContainerList[index].getRange())
50
60
 
51
61
  {
52
62